[BZOJ3307] 雨天的尾巴-----------------线段树进阶
虽然是个板子,但用到了差分思想。
Description
N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。
Solution
离线记录所有操作后把物品编号离散化,
之后修改路径信息时用到了点差分的思想。在线段树中记录差分数据,最后由叶节点开始合并,通过子树求和算出该点实际数据。
每次更改时只在两端点处加1,在lca处减1,再在lca父亲处减1即可。应该很好理解。
另外,应用边差分时,要现将边权化为点权,之后在两端点处加,在lca处减,无需更改lca父亲。(虽然这题没用到
具体看代码实现:
1 #include<bits/stdc++.h> 2 #define debug cout<<"wrong"<<endl 3 using namespace std; 4 const int NN=1e5+5; 5 int n,m,to[NN<<1],nex[NN<<1],head[NN],num,x[NN],y[NN],z[NN],ans[NN]; 6 int dep[NN],f[NN][60],tmp[NN],ext,logg,rt[NN]; 7 inline int read(){ 8 int x=0,f=1; 9 char ch=getchar(); 10 while(ch<'0'||ch>'9'){ 11 if(ch=='-') f=-1; 12 ch=getchar(); 13 } 14 while(ch>='0'&&ch<='9'){ 15 x=(x<<1)+(x<<3)+(ch^48); 16 ch=getchar(); 17 } 18 return x*f; 19 } 20 inline void add(int a,int b){ 21 to[++num]=b; nex[num]=head[a]; head[a]=num; 22 to[++num]=a; nex[num]=head[b]; head[b]=num; 23 } 24 inline int lca(int a,int b){ 25 if(dep[a]>dep[b]) swap(a,b); 26 for(int i=logg;i>=0;i--) 27 if(dep[f[b][i]]>=dep[a]) b=f[b][i]; 28 if(a==b) return a; 29 for(int i=logg;i>=0;i--) 30 if(f[a][i]!=f[b][i]) a=f[a][i], b=f[b][i]; 31 return f[a][0]; 32 } 33 void write(int x){ 34 if(x<0) putchar('-'), x=-x; 35 if(x>9) write(x/10); 36 putchar(x%10+'0'); 37 } 38 void init(){ 39 n=read(); m=read(); 40 for(int i=1;i<n;i++) add(read(),read()); 41 for(int i=1;i<=m;i++) x[i]=read(), y[i]=read(), tmp[i]=z[i]=read(); 42 43 sort(tmp+1,tmp+1+m); 44 ext=unique(tmp+1,tmp+1+m)-tmp-1; 45 for(int i=1;i<=m;i++) z[i]=lower_bound(tmp+1,tmp+ext+1,z[i])-tmp; 46 47 queue<int> q; 48 dep[1]=1; logg=log2(n)+1; q.push(1); 49 while(!q.empty()){ 50 int a=q.front(); q.pop(); 51 for(int i=head[a];i;i=nex[i]){ 52 int b=to[i]; 53 if(dep[b]) continue; 54 dep[b]=dep[a]+1; f[b][0]=a; 55 for(int j=1;j<=logg;j++) f[b][j]=f[f[b][j-1]][j-1]; 56 q.push(b); 57 } 58 } 59 } 60 struct node{ 61 int seg,ls[NN*60],rs[NN*60],typ[NN*60],sum[NN*60]; 62 void pushup(int x){ 63 if(sum[ls[x]]>=sum[rs[x]]) sum[x]=sum[ls[x]], typ[x]=typ[ls[x]]; 64 else sum[x]=sum[rs[x]], typ[x]=typ[rs[x]]; 65 } 66 void insert(int &x,int l,int r,int pos,int v){ 67 if(!x) x=++seg; 68 if(l==r){ 69 typ[x]=pos; 70 sum[x]+=v; 71 return; 72 } 73 int mid=(l+r)>>1; 74 if(pos<=mid) insert(ls[x],l,mid,pos,v); 75 else insert(rs[x],mid+1,r,pos,v); 76 pushup(x); 77 } 78 void marge(int &x,int y,int l,int r){ 79 if(!x||!y){ x=x+y; return; } 80 if(l==r){ sum[x]+=sum[y]; typ[x]=l; return; } 81 int mid=(l+r)>>1; 82 marge(ls[x],ls[y],l,mid); 83 marge(rs[x],rs[y],mid+1,r); 84 pushup(x); 85 } 86 }segt; 87 void dfs(int fa,int st){ 88 for(int i=head[st];i;i=nex[i]){ 89 int t=to[i]; 90 if(t==fa) continue; 91 dfs(st,t); 92 segt.marge(rt[st],rt[t],1,ext); 93 } 94 if(segt.sum[rt[st]]) ans[st]=tmp[segt.typ[rt[st]]]; 95 } 96 int main(){ 97 init(); 98 for(int i=1;i<=m;i++){ 99 int ca=lca(x[i],y[i]); 100 segt.insert(rt[x[i]],1,ext,z[i],1); 101 segt.insert(rt[y[i]],1,ext,z[i],1); 102 segt.insert(rt[ca],1,ext,z[i],-1); 103 if(f[ca][0]) segt.insert(rt[f[ca][0]],1,ext,z[i],-1); 104 } 105 dfs(0,1); 106 for(int i=1;i<=n;i++) 107 write(ans[i]), putchar('\n'); 108 return 0; 109 }