zoukankan      html  css  js  c++  java
  • 【BZOJ4940】【YNOI2016】这是我自己的发明

    阅读此篇文章前请先跟我大喊三声:dllxl!dllxl!dllxl!

    咳咳。

    题意:

    Description

    给一个树,n 个点,有点权,初始根是 1。
    m 个操作,每次操作:
    1. 将树根换为 x。
    2. 给出两个点 x,y,从 x 的子树中选每一个点,y 的子树中选每一个点,如果两个点点权相等,ans++,求 ans。

    Input

    第一行两个数表示 n,m。
    第二行 n 个数,表示每个点的点权 a[i]。
    之后 n - 1 行 , 每行两个数 x , y , 表示一条边
    之后 m 行,每行为 1 x 或者 2 x y。
    1 x,表示将根变成 x点。
    2 x y,表示查询 x 点的子树与 y 点的子树。
    n <= 100000 , m <= 500000 , 1 <= a[i] <= 1000000000

    Output

    对于每个询问,输出一个数表示答案。

    题解:

    非常不推荐去阅读原题面(看完题面就知道出题人系列)

    众所周知,云南省选全是毒瘤数据结构题

    其实这是一道BZOJ二合一。。。BZOJ3083 遥远的国度+BZOJ5016一个简单的询问(题解咕咕咕中)

    如果没有换根操作,先来考虑如何处理询问(BZOJ5016):

    首先按照dfs序把问题转化到序列上,询问就变成了选取序列中的两个区间,答案即为在两个区间中出现过的每个数分别在两个区间出现次数的乘积;

    用公式表达就是:

    $ans=sumlimits_{x=1}^{infty}sum(l_1,r_1,x) imes sum(l_2,r_2,x)$,其中$sum(l,r,x)$表示数字$x$在区间$[l,r]$中出现的次数。

    这个东西。。。不好处理啊。。。

    一般这种多组询问且不知所云不好维护的东西都会想到分块,然后快(du)乐(liu)莫队?

    那就推一推前缀形式:

    $ans=sumlimits_{x=1}^{infty}sum(l_1,r_1,x) imes sum(l_2,r_2,x)$

    $=sumlimits_{x=1}^{infty}(sum(1,r_1,x)-sum(1,l_1-1,x)) imes(sum(1,r_2,x)-sum(1,l_2-1,x))$

    $=sumlimits_{x=1}^{infty}sum(1,r_1,x)·sum(1,r_2,x)-sum(1,r_1,x)·sum(1,l_2-1,x)-sum(1,l_1-1,x)·sum(1,r_2,x)+sum(1,l_1-1,x)·sum(1,l_2-1,x)$

    设$f(n,m)=sumlimits_{x=1}^{infty}sum(1,n,x)·sum(1,m,x)$

    则$ans=f(r_1,r_2)-f(r_1,l_2-1)-f(l_1-1,r_2)+f(l_1-1,l_2-1)$

    所以可以询问一拆四然后直接上莫队……

    然后看换根(BZOJ3083):

    数据结构学傻了->这题一定能用LCT!

    啊LCT不能维护子树信息……

    数据结构学傻了*2->换根一定能用树剖记录!

    啊dfs序会变然后就不能维护了……

    因此我们要大力分类讨论:

    设根为root,所求子树的根为rt

    1.root==rt:continue;

    2.root不在rt的子树中:即换根后rt子树中的dfs顺序不会变,所以直接遍历即可;

    3.rt在root的子树中:

    分析此时的dfs顺序:应该是从root开始,访问到rt的子节点中是root的祖先的节点(记为点F),再访问rt,最后才是其它节点。那么在rt之前访问到的只有F的子树,其它的都是rt子树中的节点。众所周知子树dfs序连续,所以查询rt此时的子树就相当于查询线段树中$[1,l-1]$和$[r+1,n]$中的节点。

    所以只有第三种情况特殊求一个F,然后直接维护即可;

    求点F可以用树上倍增,当然在bzoj3083原题中是树剖就可以用树剖找。

    然后就可以喜闻乐见的把两题拼在一起,码码码~

    要注意的是由于换根的三种情况比较麻烦,莫队要拆成九个询问,于是常数upup

    最后的时间复杂度是$O(nsqrt{m})$,原题由于友(du)善(liu)出题人lxl的无私馈赠因此要大力卡常+调参+fread、fwrite才能过,而小视野非常良心的开了两倍时限,于是就开心过掉啦~

    代码:

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<cmath>
      6 #include<queue>
      7 #define inf 2147483647
      8 #define eps 1e-9
      9 using namespace std;
     10 //typedef long long ll;
     11 struct edge{
     12     int v,next;
     13 }a[200001];
     14 struct nd{
     15     int x,id;
     16     friend bool operator <(nd a,nd b){
     17         return a.x<b.x;
     18     }
     19 }s[200001];
     20 int BLK,n,m,op,u,v,l,r,rt=1,tot=0,tim=0,cnt=0,tmp=0,head[200001],ans[500001],pos[200001],cl[200001],ll[200001],rr[200001],num[200001],in[200001],out[200001],dep[200001],fa[200001][20];
     21 bool isans[500001];
     22 struct task{
     23     int l,r,op,id;
     24     friend bool operator <(task a,task b){
     25         return pos[a.l]==pos[b.l]?pos[a.r]<pos[b.r]:pos[a.l]<pos[b.l];
     26     }
     27 }t[4500001];
     28 void add(int u,int v){
     29     a[++tot].v=v;
     30     a[tot].next=head[u];
     31     head[u]=tot;
     32 }
     33 void dfs(int u,int ff,int dpt){
     34     in[u]=++tim;
     35     dep[u]=dpt;
     36     fa[u][0]=ff;
     37     for(int i=1;i<=19;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
     38     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
     39         int v=a[tmp].v;
     40         if(v!=ff){
     41             dfs(v,u,dpt+1); 
     42         }
     43     }
     44     out[u]=tim;
     45 }
     46 /*int lca(int u,int v){
     47     if(dep[u]<dep[v])swap(u,v);
     48     int l=dep[u]-dep[v];
     49     for(int i=19;i>=0;i--){
     50         if((1<<i)&l)u=fa[u][i];
     51     }
     52     if(u==v)return u;
     53     for(int i=19;i>=0;i--){
     54         if(fa[u][i]!=fa[v][i]){
     55             u=fa[u][i],v=fa[v][i];
     56         }
     57     }
     58     return fa[u][0];
     59 }*/
     60 int get(int u){
     61     return (dep[u]<dep[rt]&&in[u]<=in[rt]&&in[rt]<=out[u])?u:rt;
     62 }
     63 int getfa(int u,int l){
     64     for(int i=19;i>=0;i--){
     65         if((1<<i)&l)u=fa[u][i];
     66     }
     67     return u;
     68 }
     69 void mv1l(int x){
     70     tmp+=rr[cl[x]];
     71     ll[cl[x]]++;
     72 }
     73 void mv2l(int x){
     74     tmp-=rr[cl[x]];
     75     ll[cl[x]]--;
     76 }
     77 void mv1r(int x){
     78     tmp+=ll[cl[x]];
     79     rr[cl[x]]++;
     80 }
     81 void mv2r(int x){
     82     tmp-=ll[cl[x]]; 
     83     rr[cl[x]]--;
     84 }
     85 int main(){
     86     memset(head,-1,sizeof(head));
     87     memset(isans,0,sizeof(isans));
     88     scanf("%d%d",&n,&m);
     89     BLK=(int)sqrt(n);
     90     for(int i=1;i<=n;i++)pos[i]=(i-1)/BLK+1;
     91     for(int i=1;i<=n;i++){
     92         scanf("%d",&s[i].x);
     93         s[i].id=i;
     94     }
     95     for(int i=1;i<n;i++){
     96         scanf("%d%d",&u,&v);
     97         add(u,v);
     98         add(v,u);
     99     }
    100     dfs(1,0,1);
    101     sort(s+1,s+n+1);
    102     for(int i=1;i<=n;i++){
    103         if(s[i].x!=s[i-1].x)cnt++;
    104         cl[in[s[i].id]]=cnt;
    105     }
    106     cnt=0;
    107     for(int i=1;i<=m;i++){
    108         scanf("%d%d",&op,&u);
    109         if(op==1)rt=u;
    110         else{
    111             scanf("%d",&v);
    112             isans[i]=true;
    113             if(u==v&&u==rt){
    114                 t[++cnt]=(task){n,n,1,i};
    115                 continue;
    116             }
    117             if(u!=v&&v==rt)swap(u,v);
    118             int fu=get(u),fv=get(v);
    119             if(u!=v&&u==rt){
    120                 if(fv==v){
    121                     v=getfa(rt,dep[rt]-dep[v]-1);
    122                     t[++cnt]=(task){n,in[v]-1,1,i};
    123                     t[++cnt]=(task){n,n,1,i};
    124                     t[++cnt]=(task){n,out[v],-1,i};
    125                 }else{
    126                     t[++cnt]=(task){n,out[v],1,i};
    127                     t[++cnt]=(task){n,in[v]-1,-1,i};
    128                 }
    129                 continue;
    130             }
    131             if(fu==u&&fv!=v){
    132                 swap(u,v);
    133                 swap(fu,fv);
    134             }
    135             if(fu!=u&&fv!=v){
    136                 t[++cnt]=(task){out[u],out[v],1,i};
    137                 t[++cnt]=(task){out[u],in[v]-1,-1,i};
    138                 t[++cnt]=(task){in[u]-1,in[v]-1,1,i};
    139                 t[++cnt]=(task){in[u]-1,out[v],-1,i};                
    140             }else if(fu!=u&&fv==v){
    141                 v=getfa(rt,dep[rt]-dep[v]-1);
    142                 t[++cnt]=(task){out[u],in[v]-1,1,i};
    143                 t[++cnt]=(task){out[u],n,1,i};
    144                 t[++cnt]=(task){out[u],out[v],-1,i};
    145                 t[++cnt]=(task){in[u]-1,in[v]-1,-1,i};
    146                 t[++cnt]=(task){in[u]-1,n,-1,i};
    147                 t[++cnt]=(task){in[u]-1,out[v],1,i};
    148             }else{
    149                 u=getfa(rt,dep[rt]-dep[u]-1);
    150                 v=getfa(rt,dep[rt]-dep[v]-1);
    151                 t[++cnt]=(task){n,in[v]-1,1,i};
    152                 t[++cnt]=(task){n,n,1,i};
    153                 t[++cnt]=(task){n,out[v],-1,i};
    154                 t[++cnt]=(task){out[u],in[v]-1,-1,i};
    155                 t[++cnt]=(task){out[u],n,-1,i};
    156                 t[++cnt]=(task){out[u],out[v],1,i};
    157                 t[++cnt]=(task){in[u]-1,in[v]-1,1,i};
    158                 t[++cnt]=(task){in[u]-1,n,1,i};
    159                 t[++cnt]=(task){in[u]-1,out[v],-1,i};
    160             }
    161         }
    162     }
    163     sort(t+1,t+cnt+1);
    164     l=t[1].l,r=t[1].r;
    165     for(int i=1;i<=l;i++)ll[cl[i]]++;
    166     for(int i=1;i<=r;i++){
    167         rr[cl[i]]++;
    168         tmp+=ll[cl[i]];
    169     }
    170     ans[t[1].id]+=tmp*t[1].op;
    171     for(int i=2;i<=cnt;i++){
    172         while(l<t[i].l)mv1l(++l);
    173         while(l>t[i].l)mv2l(l--);
    174         while(r<t[i].r)mv1r(++r);
    175         while(r>t[i].r)mv2r(r--);
    176         ans[t[i].id]+=tmp*t[i].op;
    177     }
    178     for(int i=1;i<=m;i++){
    179         if(isans[i])printf("%d
    ",ans[i]);
    180     }
    181     return 0;
    182 } 
  • 相关阅读:
    推荐一个简洁优雅的博客系统,farbox
    flash从数据流判断图片格式防止xss攻击
    iBatis框架batch处理优化 (转)
    hadoop环境中误删除tmp文件夹的恢复
    Mysql04
    MapReduce中文翻译
    Big Table中文翻译
    GFS中文翻译
    HDFS读写流程
    两个网卡的设置
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9819077.html
Copyright © 2011-2022 走看看