[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 }
View Code

 

posted @ 2021-06-13 15:25  keen_z  阅读(38)  评论(0编辑  收藏  举报