problem list
D 萝莉理论计算机科学家
- 有点恶心,第一感觉是线段树的一定是走火入魔了(比如我)
- 实际上是差分约束,可以用dfs或并查集来做,并查集不能压缩路径
- 并查集更艺术些效率更高些~
- g[x]表示从节点x到根节点的路径上的数值总和(当做向量来理解)
- c[x]表示从节点x到邻近父节点的数值
- g[x] = c[x] + g[fx] ;
- c[fy] = g[x] + w - g[y];
- 差分约束也是在向量计算这里体现出来的
- 判定矛盾的条件则是当两个端点的根节点一致时
- g[y]-g[x] != w[i] -> ans=0
- 看数据量知道要离散化处理
- 还要注意的是题目里讲的是每个节点都是有数值的,数据代指一段节点总和的值 [u,v]==w。实际上如果把节点的值当做木板长度,第u到第v个木板总长是w就不难理解,这里在实际计算过程中要v[i]++或u[i]–,总是要对节点区间增1,就和线段树里面对于连续区间维护的操作一个道理。(这个最容易忽略,很容易漏掉。要是前面的都完成的很好,这里出错以至于全盘重做就很僵硬)
- 恩,要感谢LCJ,我俩一起商量完善的思路,之后我给实现了下下~
#include <bits/stdc++.h>
using namespace std;
typedef long long LL ;
typedef unsigned long long ULL ;
const int maxn = 100000 + 10;
const int inf = 0x3f3f3f3f ;
const int npos = -1 ;
const double eps = 1e-20 ;
int m, n, ans;
int u[maxn<<1], v[maxn<<1], num[maxn<<1], f[maxn<<1];
LL w[maxn<<1], c[maxn<<1], g[maxn<<1];
std::map< int, int > mp;
int Find(int x){
int f1=f[x], f2=x;
if(f1!=f2){
f2=Find(f1);
}
g[x]=c[x]+g[f1];
return f2;
}
void Union(int x, int fx, int y, int fy, LL z){
f[fy]=fx;
c[fy]=g[x]+z-g[y];
}
int main(){
while(~scanf("%d",&m)){
ans=1;
n=0;
mp.clear();
for(int i=1;i<=m;i++){
scanf("%d %d %lld",&u[i],&v[i],&w[i]);
v[i]++;
if(!mp.count(u[i]))
{mp.insert(make_pair(u[i],1));num[++n]=u[i];}
if(!mp.count(v[i]))
{mp.insert(make_pair(v[i],1));num[++n]=v[i];}
}
sort(num+1,num+1+n);
for(int i=1;i<=n;i++){
f[i]=i;
g[i]=0;
c[i]=0;
}
for(int i=1;i<=m;i++){
int x=lower_bound(num+1,num+1+n,u[i])-num;
int y=lower_bound(num+1,num+1+n,v[i])-num;
int fx=Find(x), fy=Find(y);
if(fx==fy){
if(g[y]-g[x]!=w[i]){
ans=0;
break;
}
}else{
Union(x,fx,y,fy,w[i]);
}
}
puts(ans?"2333!(=v=)":"666~~~(=_=)");
}
return 0;
}