雨天的尾巴——树上差分+动态开点线段树(合并)+离散化

题目链接:

https://www.acwing.com/problem/content/submission/code_detail/191343/

思路:

  如果物品类型只有一种直接差分,但是物品有多种,而且还要求最值,便在每个节点开一个线段树(最开始仅仅维护差分数组,为节省空间,只能动态开点)。

执行树上差分,最后线段树合并,即可求出每个节点最值。还要注意线段树维护的区间太大会超时,需要离散化。

ps:看了思路也调了n久

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N=100000+5;
  4 int INF;
  5 int n,m;
  6 
  7 int head[N],ver[2*N],nex[2*N],tot=0;
  8 
  9 inline void add(int x,int y)
 10 {
 11     ver[++tot]=y;
 12     nex[tot]=head[x];
 13     head[x]=tot;
 14 }
 15 
 16 int d[N],f[N][20],t;
 17 void bfs()
 18 {
 19     t=log(n)/log(2)+1;
 20     d[1]=1;
 21     queue<int> q;
 22     q.push(1);
 23     while(!q.empty())
 24     {
 25         int x=q.front();
 26         q.pop();
 27         for(int i=head[x];i;i=nex[i])
 28         {
 29             int y=ver[i];
 30             if(d[y])
 31                 continue;
 32             d[y]=d[x]+1;
 33             f[y][0]=x;
 34             for(int i=1;i<=t;++i)
 35                 f[y][i]=f[f[y][i-1]][i-1];
 36             q.push(y);
 37         }
 38     }
 39 }
 40 
 41 int lca(int x,int y)
 42 {
 43     if(d[x]<d[y])swap(x,y);
 44     if(d[x]>d[y])
 45         for(int i=t;i>=0;--i)
 46             if(d[f[x][i]]>=d[y])x=f[x][i];
 47     if(x==y)
 48         return x;
 49     for(int i=t;i>=0;--i)
 50         if(f[x][i]!=f[y][i])
 51             x=f[x][i],y=f[y][i];
 52     return f[x][0];
 53 }
 54 
 55 struct SegmentTree
 56 {
 57     int dat,id,lc,rc;
 58 };
 59 
 60 SegmentTree tree[4*N*16];
 61 int tot2=0;
 62 
 63 void pushup(int p)
 64 {
 65     if(tree[tree[p].lc].dat>=tree[tree[p].rc].dat)
 66     {
 67         tree[p].dat=tree[tree[p].lc].dat;
 68         tree[p].id=tree[tree[p].lc].id;
 69     }
 70     else
 71     {
 72         tree[p].dat=tree[tree[p].rc].dat;
 73         tree[p].id=tree[tree[p].rc].id;
 74     }
 75 }
 76 
 77 void change(int pos,int v,int p,int l,int r)
 78 {
 79     if(r-l==1)
 80     {
 81         tree[p].dat+=v;
 82         tree[p].id=pos;
 83         return;
 84     }
 85     int m=(l+r)>>1;
 86     if(pos<m)
 87     {
 88         if(!tree[p].lc)tree[p].lc=++tot2;
 89         change(pos,v,tree[p].lc,l,m);
 90     }
 91     else
 92     {
 93         if(!tree[p].rc)tree[p].rc=++tot2;
 94         change(pos,v,tree[p].rc,m,r);
 95     }
 96     pushup(p);
 97 }
 98 
 99 int merge(int p,int q,int l,int r)
100 {
101     if(!p)return q;
102     if(!q)return p;
103     if(r-l==1)
104     {
105         tree[p].dat+=tree[q].dat;
106         return p;
107     }
108 
109     int m=(l+r)>>1;
110 
111     tree[p].lc=merge(tree[p].lc,tree[q].lc,l,m);
112     tree[p].rc=merge(tree[p].rc,tree[q].rc,m,r);
113 
114     pushup(p);
115     return p;
116 }
117 
118 int ans[N],vis[N];
119 
120 void dfs(int x)
121 {
122     vis[x]=1;
123     for(int i=head[x];i;i=nex[i])
124     {
125         int y=ver[i];
126         if(vis[y])
127             continue;
128         dfs(y);
129         merge(x,y,0,INF);
130     }
131     ans[x]=tree[x].id;
132 }
133 
134 int xx[N],yy[N],zz[N];
135 int disc[N],tot3;
136 
137 int main()
138 {
139     scanf("%d%d",&n,&m);
140 
141     for(int i=1;i<n;++i)
142     {
143         int x,y;
144         scanf("%d%d",&x,&y);
145         add(x,y);
146         add(y,x);
147     }
148     bfs();
149     tot2=n;
150 
151     for(int i=0;i<m;++i)
152     {
153         scanf("%d%d%d",xx+i,yy+i,zz+i);
154         disc[++tot3]=zz[i];
155     }
156     ++tot3;
157     sort(disc,disc+tot3);
158     INF=unique(disc,disc+tot3)-disc;
159 
160     for(int i=0;i<m;++i)
161     {
162         int x,y,z;
163         x=xx[i];
164         y=yy[i];
165         z=lower_bound(disc,disc+INF,zz[i])-disc;
166         int anc=lca(x,y);
167         change(z,1,x,0,INF);
168         change(z,1,y,0,INF);
169         change(z,-1,anc,0,INF);
170         if(anc!=1)
171         change(z,-1,f[anc][0],0,INF);
172     }
173 
174     dfs(1);
175     for(int i=1;i<=n;++i)
176         printf("%d\n",disc[ans[i]]);
177 
178     return 0;
179 }
View Code

猜你喜欢

转载自www.cnblogs.com/judp/p/11253898.html
今日推荐