洛谷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 }