bzoj3307 雨天的尾巴题解及改题过程(线段树合并+lca+树上差分)
题目描述
输入格式
输出格式
----------------------------------van美分界线----------------------------------
先%一发pa大佬考试A掉这题
%%%pa
考试时刚看到这题时觉得和之前的考试题松鼠的新家(此坑未填)很像,因为都是对树上的一条链进行修改操作
所以很容易想到树上差分(其实树剖也可以但蒟蒻博主并不会),具体讲就是将链的两端加一,将lca和lca父亲节点减一。
然后我们可以看到他是询问数量所以可以想到在每一个节点建一棵权值线段树来维护信息。
又看到1e9的范围瞬间吓尿,跑去码T1,其实只要离散化一下就可以,因此我们不仅需要维护每一个节点的最大值,还要维护最大值出现的位置,这样比较方便输出答案,建立对应关系即可。
最后dfs统计答案即可,就是从叶节点往上不断merge。
最后要注意的一点就是和线段树有关的数组一定要开大一些,本人亲测要1e5×60,临接表数组开二倍(都这时候了我还犯这么低级错误,真沙雕)。
回想一下这题也没那么难,但我还是断断续续调了得有5.6节课,沙雕错误百出。具体沙雕错误代码里都有注释(大佬自动忽略即可,勿喷)。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 const int N=1e5+10; 9 int n,m;int tot;int t; 10 int first[N],nex[N*2],to[N*2],cnt,d[N],root[N*20*3],v[N],f[N][22],sum[N*20*3],posm[N*20*3],ls[N*20*3],rs[N*20*3],ans[N],x[N],yy[N],zz[N],num[N]; 11 void add(int a,int b){ 12 to[++tot]=b;nex[tot]=first[a];first[a]=tot; 13 } 14 void bfs(int x){ 15 queue<int> q; 16 q.push(x);d[x]=1; 17 while(!q.empty()){ 18 int x=q.front();q.pop(); 19 for(int i=first[x];i;i=nex[i]){ 20 int y=to[i]; 21 if(d[y]) continue; 22 d[y]=d[x]+1; 23 f[y][0]=x; 24 for(int j=1;j<=t;j++) 25 f[y][j]=f[f[y][j-1]][j-1]; 26 q.push(y); 27 } 28 } 29 } 30 int Lca(int x,int y){ 31 if(d[y]<d[x]) swap(x,y); 32 for(int i=t;i>=0;i--){ 33 if(d[f[y][i]]>=d[x]) y=f[y][i]; 34 } 35 if(x==y) return x; 36 for(int i=t;i>=0;i--){ 37 if(f[y][i]!=f[x][i]) x=f[x][i],y=f[y][i]; 38 } 39 return f[x][0]; 40 } 41 void pushup(int x){ 42 if(sum[ls[x]]>=sum[rs[x]]) sum[x]=sum[ls[x]],posm[x]=posm[ls[x]]; 43 else sum[x]=sum[rs[x]],posm[x]=posm[rs[x]]; 44 } 45 void update(int &x,int z,int add,int l,int r){ 46 if(!x){ 47 x=++cnt; 48 } 49 if(l==r){ 50 sum[x]+=add;posm[x]=z/*z !l*/; 51 return;//void return sbsbsbsb 52 } 53 int mid=(l+r)>>1; 54 if(z<=mid){ 55 update(ls[x],z,add,l,mid);// 56 } 57 else update(rs[x],z,add,mid+1,r);//递归儿子啊喂 58 pushup(x); 59 } 60 int merge(int x,int y,int l,int r){ 61 if(!x||!y){ 62 return x+y; 63 } 64 if(l==r){ 65 sum[x]+=sum[y]; 66 return x; 67 } 68 int mid=(l+r)>>1; 69 ls[x]=merge(ls[x],ls[y],l,mid); 70 rs[x]=merge(rs[x],rs[y],mid+1,r); 71 pushup(x); 72 return x; 73 } 74 void dfs(int x){ 75 for(int i=first[x];i;i=nex[i]){ 76 int y=to[i]; 77 if(y==f[x][0]) continue; 78 //root[x]=merge(root[x],root[y],ls[x],rs[x]); my wrong way 79 dfs(y); 80 root[x]=merge(root[x],root[y],1,m); 81 } 82 if(sum[root[x]])ans[x]=num[posm[root[x]]];//num[posm[root[x]]] x wai yaojia root 83 } 84 int main(){ 85 scanf("%d%d",&n,&m); 86 t=log2(n); 87 for(int i=1;i<n;i++){ 88 int a,b; 89 scanf("%d%d",&a,&b); 90 add(a,b); 91 add(b,a); 92 } 93 bfs(1); 94 for(int i=1;i<=m;i++){ 95 scanf("%d%d%d",&x[i],&yy[i],&zz[i]); 96 num[i]=zz[i]; 97 } 98 sort(num+1,num+1+m); 99 for(int i=1;i<=m;i++){ 100 zz[i]=lower_bound(num+1,num+m/*m !n*/+1,zz[i])-num; 101 int lca=Lca(x[i],yy[i]); 102 update(root[x[i]],zz[i],1,1,m);update(root[yy[i]],zz[i],1,1,m);update(root[lca],zz[i],-1,1,m);if(f[lca][0])update(root[f[lca][0]],zz[i],-1,1,m); 103 } 104 dfs(1); 105 for(int i=1;i<=n;i++) printf("%d\n",ans[i]); 106 }
我还是太弱了,orzorz。