您的位置:首页 > 其它

洛谷 P3359 改造异或树

2017-09-16 17:14 399 查看
传送门

30分做法:(边权为0)

我一开始就在想30分做法,然后就想到了:

首先老套路,正着删边就是倒着加边。

并查集维护连通块大小,每次加边后将两个端点的size值乘起来累加答案。

20分做法:

当n<=1000时,利用xor的一个性质:a^x^x=a;

然后就可以选取一个根,一遍dfs,预处理出来每个点到根节点的距离,这样dist[x,y]=s[x]^s[y];

可以每次修改后暴力查找,然后随便搞搞就好了。

50分做法:

结合做法1和做法2。

100分做法:

给每一个块都建一个平衡树(由于我太蒟蒻了,就不自己手写了,我就用map了,虽然map慢到爆炸,但也可以将就着用吧),在每一次修改的时候用启发式合并,一边合并一边统计答案,就完美解决了。

代码:(最慢的点400ms)

#include<map>
#include<cstdio>
#define ll long long
using namespace std;
inline int read(){
int x=0;char ch=' ';
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
struct edge{
int to,next,w;
}e[200001];
map<int,int> mp[100001];
map<int,int>::iterator it;
int n,tot,x[100001],y[100001],add[100001],fa[100001],z[100001],head[100001],s[100001];
ll sum[100001],ans;

int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void addedge(int x,int y,int w){e[++tot].to=y;e[tot].next=head[x];e[tot].w=w;head[x]=tot;}
void dfs(int x,int fa){
for(int i=head[x];i;i=e[i].next){
int u=e[i].to;
if(u!=fa){
s[u]=s[x]^e[i].w;
dfs(u,x);
}
}
}

int main(){
n=read();
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<n;i++){
x[i]=read();y[i]=read();z[i]=read();
addedge(x[i],y[i],z[i]);addedge(y[i],x[i],z[i]);
}
for(int i=1;i<n;i++){add[i]=read();}
dfs(1,0);
for(int i=1;i<=n;i++)mp[i][s[i]]=1;
for(int i=n-1;i>=1;i--){
int u=find(x[add[i]]);int v=find(y[add[i]]);
if(mp[u].size()>mp[v].size())swap(u,v);
fa[u]=v;
for(it=mp[u].begin();it!=mp[u].end();++it){
ans+=1ll*mp[v][it->first]*it->second;
mp[v][it->first]+=it->second;
}
sum[i]=ans;
}
for(int i=1;i<=n;i++)printf("%lld\n",sum[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: