NOIP2016天天爱跑步

洛谷P1600 https://www.luogu.org/problem/show?pid=P1600

求完LCA傻眼了

原来可以把路径拆分成两类直线路径

一类满足deep[s[i]]=deep[j]+w[j]

另一类满足deep[s[i]]-2*deep[lca[s[i]][t[i]]]+2*n=w[j]-deep[j]+2*n(防止出现负数)

得出每个路径可以碰到的观察员的所在点深度是确定的

但是深度关系满足等式的观察员不一定可以碰到,现在来一一排除

先排除和拆分后路径不在同一条链上和比路径最低点低的观察员,用DFS序

只有拆分后路径深度比较低的点在以观察员为根的子树中的路径可以被看到

正好对应着DFS序的段查询

于是我们给每一个等式deep[s[i]]和deep[s[i]]-2*deep[lca[s[i]][t[i]]]+2*n维护个DFS序列

把每一个路径的较低点的DFS序位置给增加更新,就是点修改啦

由于用内存会大到爆炸,我们用动态线段树维护

再排除比拆分后路径的最高点还高的观察员

在路径最高点的DFS序的父节点减少更新,类似于树上的差分

有个坑

???高点为根的路径会出错???

因为根结点的父亲的DFS序为0,不在线段树的DFS序区间内,所以会有问题

那我们就特判一下

然后就完了

为了加速,我们求个重心

LCA用倍增即可,虽然Tarjan会更快点

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define N 1000010
  4 #define M 1000010
  5 #define INF 0x3f3f3f3f
  6 inline void maintain(int & a,int b){a>b? a:a=b;} 
  7 inline bool isitdigit(char c){return c<='9'&&c>='0';}
  8 inline void swapt(int & a,int & b){register int t=a;a=b;b=t;}
  9 inline int read()
 10 {
 11     register int s;register char c;
 12     while( ! isitdigit(c=getchar()));
 13     for(s=c-'0';isitdigit(c=getchar());s=(s<<1)+(s<<3)+c-'0');
 14     return s;
 15 }
 16 
 17 
 18 struct tree{
 19     int n,head[N],next[2*N],to[2*N],tot;
 20     int root,mson[N],size[N];
 21     int deep[N],father[N][22],start[N],end[N],cnt;
 22     tree()
 23     {
 24         tot=root=cnt=0;
 25         memset(head,0,sizeof(head));
 26         memset(next,0,sizeof(next));
 27         memset(to,0,sizeof(to));
 28         memset(mson,0,sizeof(mson));
 29         memset(size,0,sizeof(size));
 30         memset(deep,0,sizeof(deep));
 31         memset(father,0,sizeof(father));
 32         memset(start,0,sizeof(start));
 33         memset(end,0,sizeof(end));
 34         mson[0]=INF;
 35     }
 36     inline void add(int f,int t)
 37     {
 38         to[++tot]=t;
 39         next[tot]=head[f];
 40         head[f]=tot;
 41     }
 42     inline void input(int n){
 43         for(register int i=1;i<n;++i) 
 44         {
 45             int f=read(),t=read();
 46             add(f,t),add(t,f);
 47         }
 48     }
 49     void findroot(int i,int f)
 50     {
 51         size[i]=1;
 52         mson[i]=0;
 53         for(register int j=head[i];j;j=next[j]) if(to[j]!=f)
 54         {
 55             findroot(to[j],i);
 56             size[i]+=size[to[j]];
 57             maintain(mson[i],size[to[j]]);
 58         }
 59         maintain(mson[i],n-size[i]);
 60         root=mson[root]<mson[i]? root:i;
 61     }
 62     void dfs(int i,int f,int d)
 63     {
 64         father[i][0]=f;
 65         deep[i]=d;
 66         start[i]=++cnt;
 67         for(register int j=1;j<=20;++j) father[i][j]=father[father[i][j-1]][j-1];
 68         for(register int j=head[i];j;j=next[j]) if(to[j]!=f) dfs(to[j],i,d+1);
 69         end[i]=cnt;
 70     }
 71     inline int findlca(int x,int y)
 72     {
 73         if(deep[x]>deep[y]) swapt(x,y);
 74         for(register int i=21;i>=0;--i) if(deep[father[y][i]]>=deep[x]) y=father[y][i];
 75         if(x==y) return x;
 76         for(register int i=21;i>=0;--i) if(father[x][i]!=father[y][i]) x=father[x][i],y=father[y][i];
 77         return father[x][0];
 78     }
 79 }tree;
 80 
 81 
 82 struct segment{
 83     int root[8*N],num[30*N],lson[30*N],rson[30*N],tot;
 84     inline void clear()
 85     {
 86         memset(root,0,sizeof(root));
 87         memset(num,0,sizeof(num));
 88         memset(lson,0,sizeof(lson));
 89         memset(rson,0,sizeof(rson));
 90         tot=0;
 91     }
 92     segment()
 93     {
 94         memset(root,0,sizeof(root));
 95         memset(num,0,sizeof(num));
 96         memset(lson,0,sizeof(lson));
 97         memset(rson,0,sizeof(rson));
 98         tot=0;
 99     }
100     void addit(int p,int v,int & o,int l,int r)
101     {
102         if(!o) o=++tot;
103         if(l==r)  {num[o]+=v;return;}
104         register int mid=(l+r)>>1;
105         if(p<=mid) addit(p,v,lson[o],l,mid);
106         else addit(p,v,rson[o],mid+1,r);
107         num[o]=num[lson[o]]+num[rson[o]];
108     }
109     
110     inline void add(int p,int v,int d)
111     {
112          if(!p) return;
113         addit(p,v,root[d],1,tree.cnt);
114     }
115     int queryit(int x,int y,int & o,int l,int r)
116     {
117         if(!o) return 0;
118         if(x<=l&&r<=y) return num[o];
119         register int mid=(l+r)>>1,ans=0;
120         if(x<=mid) ans+=queryit(x,y,lson[o],l,mid);
121         if(mid<y) ans+=queryit(x,y,rson[o],mid+1,r);
122         return ans;
123     }
124     inline int query(int x,int y,int d){ return queryit(x,y,root[d],1,tree.cnt);}
125 }ask;
126 
127 int w[N],m,s[M],t[M],lca[M],res[N];
128 
129 
130 int main(){
131     tree.n=read(),m=read();
132     tree.input(tree.n);
133     tree.findroot(1,0);
134     tree.dfs(tree.root,0,1);
135     for(register int i=1;i<=tree.n;++i) scanf("%d",&w[i]);
136     for(register int i=1;i<=m;++i) scanf("%d %d",&s[i],&t[i]);
137     for(register int i=1;i<=m;++i) lca[i]=tree.findlca(s[i],t[i]);
138     for(register int i=1;i<=m;++i) 
139     {
140         ask.add(tree.start[s[i]],1,tree.deep[s[i]]);
141         ask.add(tree.start[tree.father[lca[i]][0]],-1,tree.deep[s[i]]);
142     }
143     for(register int i=1;i<=tree.n;++i) res[i]+=ask.query(tree.start[i],tree.end[i],tree.deep[i]+w[i]);
144     ask.clear();
145     for(register int i=1;i<=m;++i) 
146     {
147         ask.add(tree.start[t[i]],1,tree.deep[s[i]]-2*tree.deep[lca[i]]+2*tree.n);
148         ask.add(tree.start[lca[i]],-1,tree.deep[s[i]]-2*tree.deep[lca[i]]+2*tree.n);
149     }
150     for(register int i=1;i<=tree.n;++i) res[i]+=ask.query(tree.start[i],tree.end[i],w[i]-tree.deep[i]+2*tree.n);
151     for(register int i=1;i<=tree.n;++i) printf("%d ",res[i]);
152     return 0;
153 }

猜你喜欢

转载自www.cnblogs.com/MediocreKonjac/p/9096401.html