zoukankan      html  css  js  c++  java
  • 【集训第一天·特来卖萌】树链剖分之水水的例题

         今天学习了树链剖分并且做了几道很有意思的题。。。

          树链剖分的大致思想就是把一棵树转化成一条链(一个序列),然

    后在上面做一些处理,例如:线段树。树转链的方法大致类似于 dfs

    序,但是多了一个重边的处理。

          上水题。(题名自行google)

          1.BZOJ1036 ZJOJ2008 树的统计Count

          标准模板题,超级水0.0。。。。。。

    CODE:

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<stack>
      4 #include<queue>
      5 #include<cstring>
      6 #include<algorithm>
      7 #include<vector>
      8 #include<cmath>
      9 #define inf 0x3f3f3f3f
     10 #define ll long long
     11 #define maxn  30005
     12 #define lson u<<1,l,mid
     13 #define rson u<<1|1,mid+1,r
     14 using namespace std;
     15 int w[maxn],head[maxn],tid[maxn],size[maxn],id[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],ecnt=1,cnt;
     16 
     17 struct edge{
     18     int v,next;
     19 }e[maxn*2];
     20 
     21 void adde(int u,int v){
     22     e[ecnt].v=v;
     23     e[ecnt].next=head[u];
     24     head[u]=ecnt++;
     25 }
     26 
     27 void dfs1(int u,int pre){
     28     dep[u]=dep[pre]+1;
     29     fa[u]=pre;
     30     size[u]=1;
     31     int msum=0;
     32     for(int i=head[u];i;i=e[i].next){
     33         int v=e[i].v;
     34         if(v==pre)continue;
     35         dfs1(v,u);
     36         size[u]+=size[v];
     37         if(size[v]>msum){
     38             msum=size[v];
     39             son[u]=v;
     40         }
     41     }
     42 }
     43 
     44 void dfs2(int u,int anc){
     45     tid[u]=++cnt;
     46     top[u]=anc;
     47     id[cnt]=u;
     48     if(son[u])dfs2(son[u],anc);
     49     for(int i=head[u];i;i=e[i].next){
     50         int v=e[i].v;
     51         if(v==son[u]||v==fa[u])continue;
     52         dfs2(v,v);
     53     }
     54 }
     55 
     56 struct node{
     57     int l,r,ma,sum;
     58 }t[4*maxn];
     59 
     60 void update(int u){
     61     t[u].sum=t[u<<1].sum+t[u<<1|1].sum;
     62     t[u].ma=max(t[u<<1].ma,t[u<<1|1].ma);
     63 }
     64 
     65 void build(int u,int l,int r){
     66     t[u].l=l;
     67     t[u].r=r;
     68     if(l==r){
     69         t[u].sum=t[u].ma=w[id[l]];
     70         return;
     71     }
     72     int mid=(l+r)>>1;
     73     build(lson);
     74     build(rson);
     75     update(u);
     76 }
     77 
     78 int askmax(int u,int l,int r){
     79     if(t[u].r==r&&t[u].l==l)return t[u].ma;
     80     int mid=(t[u].l+t[u].r)>>1;
     81     if(r<=mid)return askmax(u<<1,l,r);
     82     if(l>mid)return askmax(u<<1|1,l,r);
     83     else return max(askmax(u<<1,l,mid),askmax(u<<1|1,mid+1,r));
     84 }
     85 
     86 int asksum(int u,int l,int r){
     87     if(t[u].r==r&&t[u].l==l)return t[u].sum;
     88     int mid=(t[u].l+t[u].r)>>1;
     89     if(r<=mid)return asksum(u<<1,l,r);
     90     if(l>mid)return asksum(u<<1|1,l,r);
     91     else return asksum(u<<1,l,mid)+asksum(u<<1|1,mid+1,r);
     92 }
     93 
     94 int findsum(int u,int v){
     95     int fu=top[u],fv=top[v];
     96     int tmp=0;
     97     while(fu!=fv){
     98         if(dep[fu]<dep[fv]){
     99             swap(fu,fv);
    100             swap(u,v);
    101         }
    102         tmp+=asksum(1,tid[fu],tid[u]);
    103         u=fa[fu];
    104         fu=top[u];
    105     }
    106     if(dep[u]>dep[v])swap(u,v);
    107     return tmp+asksum(1,tid[u],tid[v]);
    108 }
    109 
    110 int findmax(int u,int v){
    111     int fu=top[u],fv=top[v];
    112     int tmp=-99999999;
    113     while(fu!=fv){
    114         if(dep[fu]<dep[fv]){
    115             swap(fu,fv);
    116             swap(u,v);
    117         }
    118         tmp=max(tmp,askmax(1,tid[fu],tid[u]));
    119         u=fa[fu];
    120         fu=top[u];
    121     }
    122     if(dep[u]>dep[v])swap(u,v);
    123     return max(tmp,askmax(1,tid[u],tid[v]));
    124 }
    125 
    126 void change(int u,int k,int val){
    127     if(t[u].l==k&&t[u].r==k){
    128         t[u].ma=t[u].sum=val;
    129         return;
    130     }
    131     int mid=(t[u].l+t[u].r)>>1;
    132     if(k<=mid)change(u<<1,k,val);
    133     else change(u<<1|1,k,val);
    134     update(u);
    135 }
    136 
    137 int main(){
    138     int n,m;
    139     scanf("%d",&n);
    140     int a,b;
    141     for(int i=1;i<n;i++)scanf("%d%d",&a,&b),adde(a,b),adde(b,a);
    142     for(int i=1;i<=n;i++)scanf("%d",&w[i]),t[i].ma=-99999999;
    143     dfs1(1,0);
    144     dfs2(1,1);
    145     build(1,1,n);
    146     scanf("%d",&m);
    147     for(int i=1;i<=m;i++){
    148         char s[100];
    149         scanf("%s",s);
    150         scanf("%d%d",&a,&b);
    151         if(s[0]=='C')change(1,tid[a],b);
    152         else if(!strcmp(s,"QMAX"))printf("%d
    ",findmax(a,b));
    153         else printf("%d
    ",findsum(a,b));
    154     }
    155     return 0;
    156 }
    想不想看???

        2. BZOJ3626 LNOI2014 LCA

          这东西非常扯淡,题解和题名完全不是一个等级的东西(⊙o⊙)

      这里简单地说说思路   更多细节参考 http://www.cnblogs.com/Paul-Guderian/p/6628570.html

      ①利用铺路的思想,把题目所给的每个区间中的点都一步步走回根节点,路上经过的节点点权+1。再考虑 Z(题目要求查询的节点),从Z节点向根走,把路上经过的所有节点的权值加起来,即为所求。

      ②我们求的时 [l,r]区间内的点和Z的lca的深度和,即[l,r](z)  

      那么可用前缀思想把它转化为[1,r](z)-[1,l-1](z)

      把输入的区间存入一个结构体数组(l存一个,r再存一个,l的结构体存符号"-",r存"+"),排序。

      当走到端点值时进行操作,给所对应的询问标号加上或减去具体的答案。

          PS:通过此方法可以省时间并且符合节点遍历顺序,具体操作见代码

    CODE:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<algorithm>
      6 #define ll long long
      7 #define inf 1000000000
      8 #define mod 201314
      9 using namespace std;
     10 inline ll read()
     11 {
     12     ll x=0,f=1;char ch=getchar();
     13     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     14     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     15     return x*f;
     16 }
     17 int n,m,cnt,place;
     18 int bin[20];
     19 int son[50005],last[50005],fa[50005],belong[50005],pl[50005],deep[50005];
     20 struct edge{int to,next;}e[50005];
     21 struct que{int z,ans1,ans2;}q[50005];
     22 struct data{int num,p;bool flag;}a[100005];
     23 struct seg{int l,r,sum,tag,size;}t[200005];
     24 inline bool operator<(data a,data b)
     25 {
     26     return a.p<b.p;
     27 }
     28 inline void insert(int u,int v)
     29 {
     30     e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
     31 }
     32 void dfs1(int x)
     33 {
     34     son[x]=1;
     35     for(int i=last[x];i;i=e[i].next)
     36     {
     37         if(e[i].to==fa[x])continue;
     38         deep[e[i].to]=deep[x]+1;
     39         fa[e[i].to]=x;
     40         dfs1(e[i].to);
     41         son[x]+=son[e[i].to];
     42     }
     43 }
     44 void dfs2(int x,int chain)
     45 {
     46     belong[x]=chain;pl[x]=++place;
     47     int k=n;
     48     for(int i=last[x];i;i=e[i].next)
     49         if(e[i].to!=fa[x]&&son[e[i].to]>son[k])
     50             k=e[i].to;
     51     if(k!=n)dfs2(k,chain);
     52     for(int i=last[x];i;i=e[i].next)
     53         if(e[i].to!=fa[x]&&e[i].to!=k)
     54             dfs2(e[i].to,e[i].to);
     55 }
     56 inline void pushdown(int k)
     57 {
     58     if(t[k].l==t[k].r||!t[k].tag)return;
     59     int tag=t[k].tag;t[k].tag=0;
     60     t[k<<1].sum=t[k<<1].sum+t[k<<1].size*tag;
     61     t[k<<1|1].sum=t[k<<1|1].sum+t[k<<1|1].size*tag;
     62     t[k<<1].tag=t[k<<1].tag+tag;
     63     t[k<<1|1].tag=t[k<<1|1].tag+tag;
     64 }
     65 void build(int k,int l,int r)
     66 {
     67     t[k].l=l;t[k].r=r;t[k].size=r-l+1;
     68     if(l==r)return;
     69     int mid=(l+r)>>1;
     70     build(k<<1,l,mid);
     71     build(k<<1|1,mid+1,r);
     72 }
     73 void update(int k,int x,int y)
     74 {
     75     pushdown(k);
     76     int l=t[k].l,r=t[k].r;
     77     if(l==x&&y==r)
     78     {
     79         t[k].tag++;t[k].sum+=t[k].size;
     80         return;
     81     }
     82     int mid=(l+r)>>1;
     83     if(y<=mid)update(k<<1,x,y);
     84     else if(x>mid)update(k<<1|1,x,y);
     85     else 
     86     {
     87         update(k<<1,x,mid);
     88         update(k<<1|1,mid+1,y);
     89     }
     90     t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
     91 }
     92 void solve_update(int x,int f)
     93 {
     94     while(belong[x]!=belong[f])
     95     {
     96         update(1,pl[belong[x]],pl[x]);
     97         x=fa[belong[x]];
     98     }
     99     update(1,pl[f],pl[x]);
    100 }
    101 int query(int k,int x,int y)
    102 {
    103     pushdown(k);
    104     int l=t[k].l,r=t[k].r;
    105     if(l==x&&y==r)return t[k].sum;
    106     int mid=(l+r)>>1;
    107     if(y<=mid)return query(k<<1,x,y);
    108     else if(x>mid)return query(k<<1|1,x,y);
    109     else return query(k<<1,x,mid)+query(k<<1|1,mid+1,y);
    110 }
    111 int solve_query(int x,int f)
    112 {
    113     int sum=0;
    114     while(belong[x]!=belong[f])
    115     {
    116         sum+=query(1,pl[belong[x]],pl[x]);
    117         sum%=mod;
    118         x=fa[belong[x]];
    119     }
    120     sum+=query(1,pl[f],pl[x]);sum%=mod;
    121     return sum;
    122 }
    123 int main()
    124 {
    125     //freopen("lca.in","r",stdin);
    126     //freopen("lca.out","w",stdout);
    127     bin[0]=1;for(int i=1;i<20;i++)bin[i]=(bin[i-1]<<1);
    128     n=read();m=read();
    129     for(int i=1;i<n;i++)
    130     {
    131         int x=read();insert(x,i);
    132     }
    133     int tot=0;
    134     for(int i=1;i<=m;i++)
    135     {
    136         int l=read(),r=read();
    137         q[i].z=read();
    138         a[++tot].p=l-1;a[tot].num=i;a[tot].flag=0;
    139         a[++tot].p=r;a[tot].num=i;a[tot].flag=1;
    140     }
    141     build(1,1,n);
    142     sort(a+1,a+tot+1);
    143     dfs1(0);dfs2(0,0);
    144     int now=-1;
    145     for(int i=1;i<=tot;i++)
    146     {
    147         while(now<a[i].p)
    148         {
    149             now++;
    150             solve_update(now,0);
    151         }
    152         int t=a[i].num;
    153         if(!a[i].flag)q[t].ans1=solve_query(q[t].z,0);
    154         else q[t].ans2=solve_query(q[t].z,0);
    155     }
    156     for(int i=1;i<=m;i++)
    157         printf("%d
    ",(q[i].ans2-q[i].ans1+mod)%mod);
    158     return 0;
    159 }
    看吗??

         

      3.NOIP2015运输计划

      这个题很有意思 二分答案+树链剖分+差分数组

      大致思路:

      首先预处理出每个货物送达的初始距离,用lca(tarjan,倍增,暴力,树链剖分--方法自便)+dis数组求出。sort一遍,把距离大的放在数组后面。二分最大时间最小值,找出大于这个时间的货物然后让这些货物铺路,找出这些货物共同经过的某些路(称为共路),遍历共路,找出最长共路。若 二分的答案+此共路的长度>=最大货物运输距离,则check通过。

          另外,这个题也使用了上题铺路的思想,只不过使用差分实现的。

      的用树链剖分把这棵树映射到一条链上利用差分,每个货物进一条链时,在链的首部给通货量+1,出去时在出去的节点-1。

         PS:注意此题给的是边权,可通过下放给儿子节点的方式来转化为点权,且差分时注意  脚标+1,详见代码。

    CODE:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<algorithm>
      6 #define ll long long
      7 #define inf 1000000000
      8 #define mod 201314
      9 using namespace std;
     10 inline ll read()
     11 {
     12     ll x=0,f=1;char ch=getchar();
     13     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     14     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     15     return x*f;
     16 }
     17 int n,m,cnt,place;
     18 int bin[20];
     19 int son[50005],last[50005],fa[50005],belong[50005],pl[50005],deep[50005];
     20 struct edge{int to,next;}e[50005];
     21 struct que{int z,ans1,ans2;}q[50005];
     22 struct data{int num,p;bool flag;}a[100005];
     23 struct seg{int l,r,sum,tag,size;}t[200005];
     24 inline bool operator<(data a,data b){
     25     return a.p<b.p;
     26 }
     27 inline void insert(int u,int v){
     28     e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
     29 }
     30 void dfs1(int x){
     31     son[x]=1;
     32     for(int i=last[x];i;i=e[i].next){
     33         if(e[i].to==fa[x])continue;
     34         deep[e[i].to]=deep[x]+1;
     35         fa[e[i].to]=x;
     36         dfs1(e[i].to);
     37         son[x]+=son[e[i].to];
     38     }
     39 }
     40 void dfs2(int x,int chain){
     41     belong[x]=chain;pl[x]=++place;
     42     int k=n;
     43     for(int i=last[x];i;i=e[i].next)
     44         if(e[i].to!=fa[x]&&son[e[i].to]>son[k])
     45             k=e[i].to;
     46     if(k!=n)dfs2(k,chain);
     47     for(int i=last[x];i;i=e[i].next)
     48         if(e[i].to!=fa[x]&&e[i].to!=k)
     49             dfs2(e[i].to,e[i].to);
     50 }
     51 inline void pushdown(int k){
     52     if(t[k].l==t[k].r||!t[k].tag)return;
     53     int tag=t[k].tag;t[k].tag=0;
     54     t[k<<1].sum=t[k<<1].sum+t[k<<1].size*tag;
     55     t[k<<1|1].sum=t[k<<1|1].sum+t[k<<1|1].size*tag;
     56     t[k<<1].tag=t[k<<1].tag+tag;
     57     t[k<<1|1].tag=t[k<<1|1].tag+tag;
     58 }
     59 void build(int k,int l,int r){
     60     t[k].l=l;t[k].r=r;t[k].size=r-l+1;
     61     if(l==r)return;
     62     int mid=(l+r)>>1;
     63     build(k<<1,l,mid);
     64     build(k<<1|1,mid+1,r);
     65 }
     66 void update(int k,int x,int y){
     67     pushdown(k);
     68     int l=t[k].l,r=t[k].r;
     69     if(l==x&&y==r)
     70     {
     71         t[k].tag++;t[k].sum+=t[k].size;
     72         return;
     73     }
     74     int mid=(l+r)>>1;
     75     if(y<=mid)update(k<<1,x,y);
     76     else if(x>mid)update(k<<1|1,x,y);
     77     else {
     78         update(k<<1,x,mid);
     79         update(k<<1|1,mid+1,y);
     80     }
     81     t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
     82 }
     83 void solve_update(int x,int f){
     84     while(belong[x]!=belong[f]){
     85         update(1,pl[belong[x]],pl[x]);
     86         x=fa[belong[x]];
     87     }
     88     update(1,pl[f],pl[x]);
     89 }
     90 int query(int k,int x,int y){
     91     pushdown(k);
     92     int l=t[k].l,r=t[k].r;
     93     if(l==x&&y==r)return t[k].sum;
     94     int mid=(l+r)>>1;
     95     if(y<=mid)return query(k<<1,x,y);
     96     else if(x>mid)return query(k<<1|1,x,y);
     97     else return query(k<<1,x,mid)+query(k<<1|1,mid+1,y);
     98 }
     99 int solve_query(int x,int f)
    100 {
    101     int sum=0;
    102     while(belong[x]!=belong[f])
    103     {
    104         sum+=query(1,pl[belong[x]],pl[x]);
    105         sum%=mod;
    106         x=fa[belong[x]];
    107     }
    108     sum+=query(1,pl[f],pl[x]);sum%=mod;
    109     return sum;
    110 }
    111 int main()
    112 {
    113     bin[0]=1;for(int i=1;i<20;i++)bin[i]=(bin[i-1]<<1);
    114     n=read();m=read();
    115     for(int i=1;i<n;i++)
    116     {
    117         int x=read();insert(x,i);
    118     }
    119     int tot=0;
    120     for(int i=1;i<=m;i++)
    121     {
    122         int l=read(),r=read();
    123         q[i].z=read();
    124         a[++tot].p=l-1;a[tot].num=i;a[tot].flag=0;
    125         a[++tot].p=r;a[tot].num=i;a[tot].flag=1;
    126     }
    127     build(1,1,n);
    128     sort(a+1,a+tot+1);
    129     dfs1(0);dfs2(0,0);
    130     int now=-1;
    131     for(int i=1;i<=tot;i++)
    132     {
    133         while(now<a[i].p)
    134         {
    135             now++;
    136             solve_update(now,0);
    137         }
    138         int t=a[i].num;
    139         if(!a[i].flag)q[t].ans1=solve_query(q[t].z,0);
    140         else q[t].ans2=solve_query(q[t].z,0);
    141     }
    142     for(int i=1;i<=m;i++)
    143     printf("%d
    ",(q[i].ans2-q[i].ans1+mod)%mod);
    144     return 0;
    145 }
    想看否?

      4.BZOJ2243 SDOI2011 染色

      大致就是树链剖分+线段树(染色合并,01串覆盖的升级),非常之水,上代码。

    CODE:

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<stack>
      4 #include<queue>
      5 #include<cstring>
      6 #include<algorithm>
      7 #include<vector>
      8 #include<cmath>
      9 #define inf 0x3f3f3f3f
     10 #define ll long long
     11 #define maxn 300005
     12 #define lson u<<1,l,mid
     13 #define rson u<<1|1,mid+1,r 
     14 using namespace std;
     15 int    top[maxn],fa[maxn],tid[maxn],dep[maxn],val[maxn],dis[maxn],head[maxn],q[maxn],cov[maxn],pre[maxn],son[maxn],www[maxn],size[maxn],n,m,k=1,tot;
     16 struct edge{
     17     int v,next,w;
     18 }e[2*maxn];
     19 
     20 struct post{
     21     int len,a,b;
     22 }p[maxn];
     23 void adde(int u,int v,int w){
     24     e[k].v=v;
     25     e[k].w=w;
     26     e[k].next=head[u];
     27     head[u]=k++;
     28 }
     29 
     30 bool cmp(post a,post b){
     31     return a.len<b.len;
     32 }
     33 void dfs1(int u,int pre,int Dis){
     34     size[u]=1;
     35     dep[u]=dep[pre]+1;
     36     dis[u]=Dis;
     37     fa[u]=pre;
     38     int smax=0;
     39     for(int i=head[u];i;i=e[i].next){
     40         int v=e[i].v;
     41         if(v==pre)continue;
     42         www[v]=e[i].w;
     43         dfs1(v,u,Dis+e[i].w);
     44         size[u]+=size[v];
     45         if(size[v]>smax){
     46             smax=size[v];
     47             son[u]=v;
     48         }
     49     }
     50 }
     51 
     52 void dfs2(int u,int tt){
     53     tid[u]=++tot;
     54     top[u]=tt;
     55     val[tot]=www[u];
     56     if(son[u])dfs2(son[u],tt);
     57     for(int i=head[u];i;i=e[i].next){
     58         int v=e[i].v;
     59         if(v==fa[u]||v==son[u])continue;
     60         dfs2(v,v);
     61     }
     62 }
     63 
     64 int lca(int a,int b){
     65     int ta=top[a],tb=top[b];
     66     while(ta!=tb){
     67         if(dep[ta]<dep[tb]){
     68             swap(ta,tb);
     69             swap(a,b);
     70         }
     71         a=fa[ta];
     72         ta=top[a];
     73     }
     74     if(dep[a]<dep[b])return a;
     75     return b;
     76 }
     77 
     78 void pave(int u,int v){
     79     int tu=top[u],tv=top[v];
     80     while(tu!=tv){
     81         if(dep[tu]<dep[tv]){
     82             swap(u,v);swap(tu,tv);
     83         }
     84         cov[tid[tu]]++;cov[tid[u]+1]--;
     85         u=fa[tu];
     86         tu=top[u];
     87     }
     88     if(dep[u]>dep[v])swap(u,v);
     89     cov[tid[u]+1]++;
     90     cov[tid[v]+1]--;
     91 }
     92 bool check(int x){
     93     int sd,all=0,fail;
     94     for(int i=1;i<=m;i++){if(p[i].len>x){sd=i;fail=m-i+1;break;}}
     95     if(q[fail])return q[fail]+x>=p[m].len;
     96     for(int i=1;i<=tot;i++)cov[i]=0;
     97     for(int i=sd;i<=m;i++)pave(p[i].a,p[i].b);
     98     for(int i=1;i<=tot;i++){
     99         all+=cov[i];
    100         if(all==fail)q[fail]=max(q[fail],val[i]);
    101     }
    102     return q[fail]+x>=p[m].len;
    103 }
    104 int main(){
    105     scanf("%d%d",&n,&m);
    106     int big=0;
    107     for(int i=1;i<n;i++){
    108         int a,b,c;
    109         scanf("%d%d%d",&a,&b,&c);
    110         adde(a,b,c);
    111         adde(b,a,c);
    112     }
    113     dfs1(1,0,0);
    114     dfs2(1,1);
    115     for(int i=1;i<=m;i++){
    116         int a,b;
    117         scanf("%d%d",&a,&b);
    118         p[i].a=a;p[i].b=b;
    119         p[i].len=dis[a]+dis[b]-2*dis[(lca(a,b))];
    120         big=max(big,p[i].len);
    121     }sort(p+1,p+1+m,cmp);
    122     int l=0,r=big;
    123     while(l<r){
    124         int mid=(l+r)>>1;
    125         if(check(mid))r=mid;
    126         else l=mid+1;
    127     }
    128     printf("%d",r);
    129     return 0;
    130 }
    想看否?

       5.BZOJ2819 Nim

      妈蛋。。还搞上了博弈论,,于是 y水j老师花20min讲完了博弈论。。桑心0.0

      大致思路:

      树链剖分+线段树/树状数组+博弈论

       其实只要你懂博弈论这个题还是非常简单的(博弈论自己网上学),使用XOR可轻松搞定,每堆石子的个数为x,它的sg值也为x,直接^就行,是不是炒鸡简单?

      至于树链剖分,其实是快速查找路径(u->v),用一个线段树直接搞出每个区间的XOR值就行了23333此题就如此地水过了。

      还有就是,由于只涉及到单点修改和区间查询 ,聪明的召唤师可直接使用lowbit树状数组,秀了我一脸,懵逼ing……

      PS:不要以为之输入 Q和C 你就可以用scanf读入单个字符判断操作

      老夫就是被这个东西祸害了好久

      原因:你读入数字后还有一个回车  char c;scanf("%c",&c)后会读入一个空格,然而水水的样例还是过,这就有点坑人

      处理方法

          一:读入字符串 (scanf读入字符串会自动省略 "空格"和"回车")
      二:scanf(" %c",&c) %c前的空格千万不能省去否则就会读入 "回车" 导致程序错误

    CODE:

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cmath>
      5 #include<cstring>
      6 #include<queue>
      7 #define lson u<<1,l,mid
      8 #define rson u<<1|1,mid+1,r
      9 #define N 500005
     10 using namespace std;
     11 int val[N],id[N],top[N],tid[N],dep[N],siz[N],fa[N],son[N],head[N],n,m,k=1,tot;
     12 struct edge{int v,next;}e[2*N];
     13 struct tree{int l,r,sum;}t[4*N];
     14 int read(){
     15     char c;int x=0;c=getchar();
     16     while(c>'9'||c<'0')c=getchar();
     17     while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();
     18     return x;
     19 }
     20 
     21 void adde(int u,int v){
     22     e[k].v=v;
     23     e[k].next=head[u];
     24     head[u]=k++;
     25 }
     26 
     27 
     28 void dfs1(int u,int pre){
     29     siz[u]=1;
     30     fa[u]=pre;
     31     dep[u]=dep[pre]+1;
     32     for(int i=head[u];i;i=e[i].next){
     33         int v=e[i].v;
     34         if(v==pre)continue;
     35         dfs1(v,u);
     36         siz[u]+=siz[v];
     37         if(siz[v]>siz[son[u]])son[u]=v;
     38     }
     39 }
     40 
     41 void dfs2(int u,int tt){
     42     tid[u]=++tot;
     43     top[u]=tt;
     44     id[tot]=u;
     45     if(son[u])dfs2(son[u],tt);
     46     for(int i=head[u];i;i=e[i].next){
     47         int v=e[i].v;
     48         if(v==fa[u]||v==son[u])continue;
     49         dfs2(v,v);
     50     }
     51 }
     52 
     53 void pushup(int u){
     54     t[u].sum=t[u<<1].sum^t[u<<1|1].sum;
     55 }
     56 
     57 void build(int u,int l,int r){
     58     t[u].l=l;
     59     t[u].r=r;
     60     if(l==r){
     61         t[u].sum=val[id[l]];
     62         return;
     63     }
     64     int mid=(l+r)>>1;
     65     build(lson);
     66     build(rson);
     67     pushup(u);
     68 }
     69 
     70 void update(int u,int pos,int ch){
     71     if(t[u].l==t[u].r){
     72         t[u].sum=ch;
     73         return;
     74     }
     75     int mid=(t[u].l+t[u].r)>>1;
     76     if(pos<=mid)update(u<<1,pos,ch);
     77     else update(u<<1|1,pos,ch);
     78     pushup(u);
     79 }
     80 
     81 int query(int u,int l,int r){
     82     if(t[u].l==l&&t[u].r==r)return t[u].sum;
     83     int mid=(t[u].l+t[u].r)>>1;
     84     if(r<=mid)return query(u<<1,l,r);
     85     if(l>mid)return query(u<<1|1,l,r);
     86     return query(u<<1,l,mid)^query(u<<1|1,mid+1,r);
     87 }
     88 
     89 bool fuck(int u,int v){
     90     int ans=0;
     91     while(top[u]!=top[v]){
     92         if(dep[top[u]]<dep[top[v]])swap(u,v);
     93         ans^=query(1,tid[top[u]],tid[u]);
     94         u=fa[top[u]];
     95     }
     96     if(u==v)return ans^val[u];
     97     if(dep[u]>dep[v])swap(u,v);
     98     ans^=query(1,tid[u],tid[v]);
     99     return ans;
    100 }
    101 
    102 int main(){
    103     n=read();
    104     for(int i=1;i<=n;i++)val[i]=read();int a,b;
    105     for(int i=1;i<n;i++)a=read(),b=read(),adde(a,b),adde(b,a);
    106     dfs1(1,0);dfs2(1,1);build(1,1,tot);m=read();
    107     for(int i=1;i<=m;i++){
    108         char s[3];
    109         scanf("%s",&s);
    110         a=read();b=read();
    111         if(s[0]=='Q')fuck(a,b)?puts("Yes"):puts("No");
    112         else val[a]=b,update(1,tid[a],b);
    113     }
    114     return 0;
    115 }
    直接给你看了,,

      6.BZOJ4034 HAOI2015 树上操作

      这个题非常之水,我都懒得写它,吐槽一下,作为省选怎能这样??

      首先是树链剖分可以做,加一个dfs序(或用size数组表示儿子节点总数,对应到链上表示子树)来修改自己的子树。

      听可爱的lg鸡小盆友说此题甚至可以不用树链剖分,直接dfs序+线段树。。

      代码网上直接抄的,看不看无所谓。

    CODE:

      1 Description
      2  有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
      3 操作,分为三种:
      4 操作 1 :把某个节点 x 的点权增加 a 。
      5 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
      6 操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
      7 Input
      8  第一行包含两个整数 N, M 。表示点数和操作数。
      9 接下来一行 N 个整数,表示树中节点的初始权值。
     10 接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。
     11 再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操
     12 作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
     13 Output
     14  对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
     15 Sample Input
     16 5 5
     17 
     18 1 2 3 4 5
     19 
     20 1 2
     21 
     22 1 4
     23 
     24 2 3
     25 
     26 2 5
     27 
     28 3 3
     29 
     30 1 2 1
     31 
     32 3 5
     33 
     34 2 1 2
     35 
     36 3 3
     37 Sample Output
     38 6
     39 
     40 9
     41 
     42 13
     43 
     44 HINT
     45  对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不
     46 
     47 会超过 10^6 48 题解:树链剖分裸题,支持点修改,链查询,子树修改,子树查询。
     49 [html] view plain copy 在CODE上查看代码片派生到我的代码片
     50 #include<iostream>  
     51 #include<cstdio>  
     52 #include<cstring>  
     53 #include<algorithm>  
     54 using namespace std;  
     55 const int N=100100;  
     56 int point[N],next[N*4],belong[N],siz[N],son[N],pos[N],deep[N];  
     57 int n,m,tot=1,num=0,fa[N];  
     58 long long tr[N*4],de[N*4],r[N];  
     59 bool use[N];  
     60 struct S{  
     61     int st,en;  
     62 }aa[N*4];  
     63 inline void add(int x,int y)  
     64 {  
     65     tot+=1;next[tot]=point[x];point[x]=tot;  
     66     aa[tot].st=x;aa[tot].en=y;  
     67     tot+=1;next[tot]=point[y];point[y]=tot;  
     68     aa[tot].st=y;aa[tot].en=x;  
     69 }  
     70 inline void dfs_1(int x)  
     71 {  
     72     int i;  
     73     siz[x]=1;  
     74     use[x]=false;  
     75     for(i=point[x];i;i=next[i])  
     76       if(use[aa[i].en]){  
     77         deep[aa[i].en]=deep[x]+1;  
     78         fa[aa[i].en]=x;  
     79         dfs_1(aa[i].en);  
     80         siz[x]+=siz[aa[i].en];  
     81       }  
     82 }  
     83 inline void dfs_2(int x,int y)  
     84 {  
     85     int i,k=0;  
     86     num+=1;  
     87     pos[x]=son[x]=num;  
     88     belong[x]=y;  
     89     for(i=point[x];i;i=next[i])  
     90       if(deep[x]<deep[aa[i].en]&&siz[k]<siz[aa[i].en])  
     91         k=aa[i].en;  
     92     if(k==0) return ;  
     93     dfs_2(k,y);son[x]=max(son[k],son[x]);  
     94     for(i=point[x];i;i=next[i])  
     95       if(deep[x]<deep[aa[i].en]&&k!=aa[i].en){  
     96         dfs_2(aa[i].en,aa[i].en);  
     97         son[x]=max(son[x],son[aa[i].en]);  
     98     }  
     99 }  
    100 #define mid (l+r)/2  
    101 #define L k<<1,l,mid  
    102 #define R k<<1|1,mid+1,r  
    103 inline void paint(int k,int l,int r,long long z)  
    104 {  
    105     de[k]+=z;  
    106     tr[k]+=(r-l+1)*z;  
    107 }  
    108 inline void pushdown(int k,int l,int r)  
    109 {  
    110     if(l==r) return ;  
    111     paint(L,de[k]);  
    112     paint(R,de[k]);  
    113     de[k]=0;  
    114 }  
    115 inline void insert(int k,int l,int r,int x,long long y)  
    116 {  
    117     if(l==r&&l==x){  
    118         tr[k]+=y;  
    119         return ;  
    120     }  
    121     pushdown(k,l,r);  
    122     if(x<=mid) insert(L,x,y);  
    123     else insert(R,x,y);  
    124     tr[k]=tr[k<<1]+tr[k<<1|1];  
    125 }  
    126 inline void change(int k,int l,int r,int x,int y,long long z)  
    127 {  
    128     if(x<=l&&y>=r){  
    129         paint(k,l,r,z);  
    130         return ;  
    131     }  
    132     pushdown(k,l,r);  
    133     if(x<=mid) change(L,x,y,z);  
    134     if(y>mid) change(R,x,y,z);  
    135     tr[k]=tr[k<<1]+tr[k<<1|1];  
    136 }  
    137 inline long long qurey(int k,int l,int r,int x,int y)  
    138 {  
    139     long long sum=0;  
    140     if(x<=l&&y>=r) return tr[k];  
    141     pushdown(k,l,r);  
    142     if(x<=mid) sum+=qurey(L,x,y);  
    143     if(y>mid) sum+=qurey(R,x,y);  
    144     return sum;  
    145 }  
    146 inline long long ask(int x,int y)  
    147 {  
    148     long long sum=0;  
    149     while(belong[x]!=belong[y]){  
    150         sum+=qurey(1,1,n,pos[belong[x]],pos[x]);  
    151         x=fa[belong[x]];  
    152     }  
    153     sum+=qurey(1,1,n,pos[y],pos[x]);  
    154     return sum;  
    155 }  
    156 int main()  
    157 {  
    158     int i,j,x,t,root;  
    159     long long y;  
    160     memset(use,1,sizeof(use));  
    161     scanf("%d%d",&n,&m);  
    162     for(i=1;i<=n;++i) scanf("%lld",&r[i]);  
    163     for(i=1;i<n;++i){  
    164         scanf("%d%d",&x,&y);  
    165         add(x,y);  
    166     }  
    167     dfs_1(1);  
    168     dfs_2(1,1);  
    169     for(i=1;i<=n;++i){  
    170         insert(1,1,n,pos[i],r[i]);  
    171         if(deep[i]==0) root=i;  
    172     }  
    173     while(m--){  
    174         scanf("%d",&t);  
    175         if(t==1||t==2){  
    176             scanf("%d%lld",&x,&y);  
    177             if(t==1) insert(1,1,n,pos[x],y);  
    178             if(t==2) change(1,1,n,pos[x],son[x],y);  
    179         }  
    180         else{  
    181             scanf("%d",&x);  
    182             printf("%lld
    ",ask(x,root));  
    183         }  
    184     }  
    185 }  
    View Code

    至此,愉快的一天就结束了。很累很充实哈!

    哈哈哈哈即使是停掉常规课学竞赛老子依然写完了生物和英语作业,屌否?

    现在是22:20,可爱的lg鸡,美腻的张姐,和猥琐的lence_鸡正在CS:GO

    勤奋的二哥仍然在学习KMP

    我花了一个小时写完了这个博客,快哉快哉。。。

      










    If you live in the echo,
    your heart never beats as loud.
    如果你生活在回声里,
    你的心跳声永远不会轰鸣作响。
  • 相关阅读:
    系统编码、文件编码与python系统编码
    python2判断编码格式
    android: 对apk进行系统签名
    android: 对普通的apk应用进行签名
    android studio: 设置单条注释不换行
    Gradle: Could not determine the dependencies of task ':app:processDebugResources'解决(转)
    android Dialog: 去除dialog 顶部 蓝色的线
    android:Error:” ” is not translated in “en” (English) [MissingTranslation]处理方法(转)
    android: 通过Intent筛选多种类型文件
    GIt: git rebase 和 git merge 的区别 (转)
  • 原文地址:https://www.cnblogs.com/wsy01/p/6629190.html
Copyright © 2011-2022 走看看