【JLOI2014】松鼠的新家

这道题洛谷给的标签是LCA,线段树,树链剖分。

当然LCA+树上差分能通过这道题,但出现在树链剖分当中,我决定用树链剖分解决

显然这是一道裸的树链剖分。树剖之后进行区间修改,单点查询操作。(这道题线段树都不用build……23333)

我们按照题目给的顺序给这一棵"树"放上糖果,当然注意重复的部分要减掉,最后对每一个点进行查询即可。

【JLOI2014】松鼠的新家
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 typedef long long ll;
  5 #define N 300010
  6 inline int read() {
  7     int ret=0,f=1;
  8     char c=getchar();
  9     while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
 10     while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
 11     return ret*f;
 12 }
 13 using namespace std;
 14 int n;
 15 struct edge {
 16     int next,to;
 17 }a[N<<1];
 18 int num,head[N<<1];
 19 int fa[N],son[N],top[N],d[N],seg[N],rev[N],tot;
 20 int sum[N<<2],tag[N<<2],size[N];
 21 int turn[N];
 22 inline void add(int from,int to) {
 23     a[++num].next=head[from]; a[num].to=to; head[from]=num;
 24     swap(from,to);
 25     a[++num].next=head[from]; a[num].to=to; head[from]=num;
 26 }
 27 void dfs1(int u,int f) {
 28     size[u]=1;
 29     fa[u]=f;
 30     d[u]=d[f]+1;
 31     for(int i=head[u];i;i=a[i].next) {
 32         int v=a[i].to;
 33         if(v==f) continue ;
 34         dfs1(v,u);
 35         size[u]+=size[v];
 36         if(size[v]>size[son[u]]) son[u]=v;
 37     }
 38 }
 39 void dfs2(int u,int f) {
 40     if(son[u]) {
 41         seg[son[u]]=++tot;
 42         rev[tot]=son[u];
 43         top[son[u]]=top[u];
 44         dfs2(son[u],u);
 45     }
 46     for(int i=head[u];i;i=a[i].next) {
 47         int v=a[i].to;
 48         if(!top[v]) {
 49             seg[v]=++tot;
 50             rev[tot]=v;
 51             top[v]=v;
 52             dfs2(v,u);
 53         }
 54     }
 55 }
 56 inline void pushdown(int now,int len) {
 57     if(!tag[now]) return ;
 58     tag[now<<1]+=tag[now];
 59     tag[now<<1|1]+=tag[now];
 60     sum[now<<1]+=tag[now]*(len-(len>>1));
 61     sum[now<<1|1]+=tag[now]*(len>>1);
 62     tag[now]=0;
 63 }
 64 void updata(int now,int l,int r,int x,int y,int v) {
 65     if(x<=l&&r<=y) {
 66         tag[now]+=v;
 67         sum[now]+=v*(r-l+1);
 68         return ;
 69     }
 70     int mid=l+r>>1;
 71     pushdown(now,r-l+1);
 72     if(x<=mid) updata(now<<1,l,mid,x,y,v);
 73     if(y>mid) updata(now<<1|1,mid+1,r,x,y,v);
 74     sum[now]=sum[now<<1]+sum[now<<1|1];
 75 }
 76 void find(int x,int y) {
 77     while(top[x]!=top[y]) {
 78         if(d[top[x]]<d[top[y]]) swap(x,y);
 79         updata(1,1,tot,seg[top[x]],seg[x],1);
 80         x=fa[top[x]];    
 81     }
 82     if(d[x]>d[y]) swap(x,y);
 83     updata(1,1,tot,seg[x],seg[y],1);
 84 }
 85 int query(int now,int l,int r,int x) {
 86     if(l==r) return sum[now];
 87     int mid=l+r>>1;
 88     pushdown(now,r-l+1);
 89     if(x<=mid) return query(now<<1,l,mid,x);
 90     else return query(now<<1|1,mid+1,r,x);
 91 }
 92 int main() {
 93     n=read();
 94     for(int i=1;i<=n;i++) turn[i]=read();
 95     for(int i=1;i<n;i++) add(read(),read());
 96     dfs1(1,0);
 97     tot=seg[1]=rev[1]=top[1]=1;
 98     dfs2(1,0);
 99 //    build(1,1,tot);
100     for(int i=1;i<n;i++) {
101         find(turn[i],turn[i+1]);
102         updata(1,1,tot,seg[turn[i+1]],seg[turn[i+1]],-1);
103     }
104     for(int i=1;i<=n;i++) {
105         printf("%d\n",query(1,1,tot,seg[i]));
106     }
107     return 0;
108 }
AC Code

 

上一篇:P3521 [POI2011]ROT-Tree Rotations


下一篇:算概率(取模处理dp)