• P3242 [HNOI2015]接水果


    题面

      将树上的路径包含问题通过dfs序转换为双关键字区间包含问题,

    进而转换为区间覆盖类问题。

      由此,我们可以通过二分得出每一个询问的答案。

      由于有多次询问,故只需要整体二分即可。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 int n,p,q,x,y,z;
      4 int head[100050],tot;
      5 int nex[100050];
      6 int ver[100050];
      7 int siz[100050];
      8 int ans[100050];
      9 int pos[200050];
     10 int tl[100050];
     11 int tr[100050];
     12 int w[100050];
     13 int t[100050],top;
     14 int bz[100050][20];
     15 int f[200050],sf;
     16 int g[200050],sg;
     17 int c[100050];
     18 void calc_add(int u,int v)
     19 {
     20     t[++top]=u;
     21     while(u<=n)
     22     {
     23         c[u]+=v;
     24         u+=u&-u;
     25     }
     26 }
     27 int calc_ask(int u)
     28 {
     29     int sum=0;
     30     while(u)
     31     {
     32         sum+=c[u];
     33         u-=u&-u; 
     34     }
     35     return sum;
     36 }
     37 void calc_clear()
     38 {
     39     while(top)
     40     {
     41         while(t[top]<=n)
     42         {
     43             c[t[top]]=0;
     44             t[top]+=t[top]&-t[top];
     45         }
     46         --top;
     47     }
     48 }
     49 struct node
     50 {
     51     int opt,x,y,l,r,val;
     52     bool operator<(const node &p )const
     53     {
     54         return x==p.x? opt<p.opt:x<p.x;
     55     }
     56 }num[200050];
     57 void add(int x,int y)
     58 {
     59     nex[++tot]=head[x];
     60     ver[tot]=y;
     61     head[x]=tot;
     62 }
     63 void dfs(int u,int fa)
     64 {
     65     tl[u]=++tot;    siz[u]=1;
     66     bz[u][0]=fa;
     67     for(int i=1;i<=18;++i)
     68         bz[u][i]=bz[bz[u][i-1]][i-1];
     69     for(int i=head[u];i;i=nex[i])
     70         if(ver[i]!=fa)
     71         {
     72             dfs(ver[i],u);
     73             siz[u]+=siz[ver[i]];
     74         }
     75     tr[u]=tl[u]+siz[u]-1;
     76 }
     77 void solve(int l,int r,int L,int R)
     78 {
     79     if(L==R)
     80     {
     81         for(int i=l;i<=r;++i)
     82             if(num[pos[i]].opt>0)
     83                 ans[num[pos[i]].opt]=w[L];
     84         return ;
     85     }
     86     int sf=0,sg=0;
     87     bool flagf=0;
     88     bool flagg=0;
     89     int mid=(L+R)>>1;
     90     for(int i=l,j;i<=r;++i)
     91     {
     92         j=pos[i];
     93         if(num[j].opt<0)
     94         {
     95             if(num[j].val<=mid)
     96             {
     97                 calc_add(num[j].l,num[j].opt+2);
     98                 calc_add(num[j].r+1,-(num[j].opt+2));
     99                 f[++sf]=j;
    100             }
    101             else
    102                 g[++sg]=j;
    103         }
    104         else
    105         {
    106             int tmp=calc_ask(num[j].y);
    107             if(tmp>=num[j].val)
    108             {
    109                 f[++sf]=j;
    110                 flagf=true;
    111             }
    112             else
    113             {
    114                 g[++sg]=j;
    115                 flagg=true;
    116                 num[j].val-=tmp;
    117             }
    118         }
    119     }
    120     calc_clear();
    121     for(int i=1;i<=sf;++i)    pos[l-1+i]=f[i];
    122     for(int i=1;i<=sg;++i)    pos[l-1+sf+i]=g[i];
    123     if(flagf)    solve(l,l-1+sf,L,mid);
    124     if(flagg)    solve(l-1+sf+1,r,mid+1,R);
    125 }
    126 void ad(int opt,int x,int l,int r)
    127 {
    128     if(l>r)    return ;
    129     ++tot;
    130     num[tot].opt=opt;
    131     num[tot].x=x;
    132     num[tot].l=l;
    133     num[tot].r=r;
    134     num[tot].val=z;
    135 }
    136 int main()
    137 {
    138     scanf("%d%d%d",&n,&p,&q);
    139     for(int i=1;i<n;++i)
    140     {
    141         scanf("%d%d",&x,&y);
    142         add(x,y);    add(y,x); 
    143     }
    144     tot=0;    dfs(1,0);    tot=0;
    145     for(int i=1;i<=p;++i)
    146     {
    147         scanf("%d%d%d",&x,&y,&z);
    148         t[++top]=z;
    149         if(tl[x]>tl[y])    swap(x,y);
    150         if(tl[x]<=tl[y]&&tr[x]>=tl[y])
    151         {
    152             int tmp=y;
    153             for(int k=18;k>=0;--k)
    154                 if(tl[bz[tmp][k]]>tl[x])
    155                     tmp=bz[tmp][k];
    156             ad(-1,1,tl[y],tr[y]);
    157             ad(-3,tl[tmp]-1+1,tl[y],tr[y]);
    158             ad(-1,tl[y],tr[tmp]+1,n);
    159             ad(-3,tr[y]+1,tr[tmp]+1,n);
    160         }
    161         else
    162         {
    163             ad(-1,tl[x],tl[y],tr[y]);
    164             ad(-3,tr[x]+1,tl[y],tr[y]);
    165         }
    166     }
    167     sort(t+1,t+top+1);
    168     top=unique(t+1,t+top+1)-t-1;
    169     for(int i=1;i<=top;++i)    w[i]=t[i];
    170     int tp=top; top=0;
    171     for(int i=1;i<=tot;++i)    num[i].val=lower_bound(t+1,t+tp+1,num[i].val)-t;
    172     for(int i=1;i<=q;++i)
    173     {
    174         ++tot;    num[tot].opt=i;
    175         scanf("%d%d%d",&num[tot].x,&num[tot].y,&num[tot].val);
    176         if(tl[num[tot].x]>tl[num[tot].y])    swap(num[tot].x,num[tot].y);
    177         num[tot].x=tl[num[tot].x];    num[tot].y=tl[num[tot].y];
    178     }
    179     sort(num+1,num+tot+1);
    180     for(int i=1;i<=tot;++i)    pos[i]=i;
    181     solve(1,tot,1,tp);
    182     for(int i=1;i<=q;++i)
    183         printf("%d
    ",ans[i]);
    184     return 0;
    185 }
    View Code
  • 相关阅读:
    linux安装nginx
    git配置多个SSH密钥
    webpack加载器安装node-sass失败的解决方法
    Vue-cli webpack打包之后index.html缺少引号的问题
    算法:一个数组中所有元素的最小公倍数
    JS 实现一个睡眠函数sleep
    剑指offer 牛客67道题集合
    剑指offer
    剑指offer
    剑指offer
  • 原文地址:https://www.cnblogs.com/wyher/p/10408569.html
Copyright © 2020-2023  润新知