• [CodeChef-QTREE6]Query on a tree VI


    题目大意:
      给你一棵黑白树,每个点默认是白色,要求支持以下两种操作:
        1.改变一个点的颜色;
        2.除去连接不同颜色的点的边,求某个点连通块的大小。

    思路:
      对原树维护两个树链剖分,
      一棵维护当点x为白色时,以它为根结点的白色的子树大小;
      另一棵维护当点x为黑色时,以它为根结点的黑色的子树大小。(两者均不考虑x的实际颜色)
      方便起见,这里我们用q表示同一个连通分量中,深度最浅的祖先。
      询问一个点时,相当于在询问q的值。
      修改一个点时,相当于在原来颜色的树剖上将x到q的路径上的所有点同时减去x同色子树的大小,然后在新的颜色的树剖上将x到q路径上的所有点同时加上x同色子树的大小。
      如果对每个点都加/减显然不方便,因此我们可以用一些数据结构(线段树/树状数组)来维护差分。
      注意这道题会卡常,要么对每一条链建线段树,要么就用树状数组。
      接下来的问题是如何找到祖先q。
      如果暴力往上找,时间复杂度是O(n)的,显然会TLE。
      假如我们能够直接判断某一个树链上的点是否是同一种颜色,那就可以直接往上跳了。
      如何直接判断?
      考虑用0代表白色,1代表黑色,如果当这条链上所有点的权值和等于这条链上结点的个数,或等于0,那么肯定是同一种颜色的。
      这样我们可以直接维护树上前缀和,询问的时候减一下就可以了。
      最后还剩半条链没法跳的时候可以二分中间的结点。

      1 #include<cstdio>
      2 #include<cctype>
      3 #include<vector>
      4 inline int getint() {
      5     char ch;
      6     while(!isdigit(ch=getchar()));
      7     int x=ch^'0';
      8     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
      9     return x;
     10 }
     11 const int V=100001;
     12 std::vector<int> e[V];
     13 inline void add_edge(const int &u,const int &v) {
     14     e[u].push_back(v);
     15 }
     16 int par[V],size[V],son[V],top[V],id[V],dep[V],id2[V],n;
     17 bool col[V];
     18 void dfs1(const int &x,const int &p) {
     19     par[x]=p;
     20     size[x]=1;
     21     dep[x]=dep[p]+1;
     22     for(unsigned i=0;i<e[x].size();i++) {
     23         const int &y=e[x][i];
     24         if(y==p) continue;
     25         dfs1(y,x);
     26         size[x]+=size[y];
     27         if(size[y]>size[son[x]]) {
     28             son[x]=y;
     29         }
     30     }
     31 }
     32 void dfs2(const int &x) {
     33     id[x]=++n;
     34     id2[n]=x;
     35     top[x]=x==son[par[x]]?top[par[x]]:x;
     36     if(son[x]) dfs2(son[x]);
     37     for(unsigned i=0;i<e[x].size();i++) {
     38         const int &y=e[x][i];
     39         if(y==par[x]||y==son[x]) continue;
     40         dfs2(y);
     41     }
     42 }
     43 class FenwickTree {
     44     private:
     45         int val[V];
     46         int lowbit(const int &x) {
     47             return x&-x;
     48         }
     49     public:
     50         void modify(int p,const int &x) {
     51             while(p<=n) {
     52                 val[p]+=x;
     53                 p+=lowbit(p);
     54             }
     55         }
     56         int query(int p) {
     57             int ret=0;
     58             while(p) {
     59                 ret+=val[p];
     60                 p-=lowbit(p);
     61             }
     62             return ret;
     63         }
     64 };
     65 FenwickTree t[3];
     66 bool check(const int &u,const int &m) {
     67     return t[2].query(id[u])-t[2].query(id[m]-1)==col[u]*(dep[u]-dep[m]+1);
     68 }
     69 inline int get_anc(int u) {
     70     while(top[u]!=1&&check(u,top[u])) {
     71         if(col[par[top[u]]]==col[u]) {
     72             u=par[top[u]];
     73         } else {
     74             return top[u];
     75         }
     76     }
     77     int l=id[top[u]],r=id[u];
     78     while(l<=r) {
     79         const int mid=(l+r)>>1;
     80         if(check(u,id2[mid])) {
     81             r=mid-1;
     82         } else {
     83             l=mid+1;
     84         }
     85     }
     86     return id2[r+1];
     87 }
     88 inline void modify2(int x,int y,const int &k,const bool &c) {
     89     while(top[x]!=top[y]) {
     90         t[c].modify(id[top[x]],k);
     91         t[c].modify(id[x]+1,-k);
     92         x=par[top[x]];
     93     }
     94     t[c].modify(id[y],k);
     95     t[c].modify(id[x]+1,-k);
     96 }
     97 inline void modify(const int &u) {
     98     if(u!=1) modify2(par[u],par[get_anc(u)],-t[col[u]].query(id[u]),col[u]);
     99     t[2].modify(id[u],col[u]?-1:1);
    100     col[u]^=true;
    101     if(u!=1) modify2(par[u],par[get_anc(u)],t[col[u]].query(id[u]),col[u]);
    102 }
    103 inline int query(const int &u) {
    104     return t[col[u]].query(id[get_anc(u)]);
    105 }
    106 int main() {
    107     int n=getint();
    108     for(register int i=1;i<n;i++) {
    109         const int u=getint(),v=getint();
    110         add_edge(u,v);
    111         add_edge(v,u);
    112     }
    113     dfs1(1,1);
    114     dfs2(1);
    115     for(register int i=1;i<=n;i++) {
    116         t[0].modify(id[i],size[i]);
    117         t[0].modify(id[i]+1,-size[i]);
    118     }
    119     t[1].modify(1,1);
    120     for(register int m=getint();m;m--) {
    121         const int t=getint(),u=getint();
    122         if(t) {
    123             modify(u);
    124         } else {
    125             printf("%d
    ",query(u));
    126         }
    127     }
    128     return 0;
    129 }
  • 相关阅读:
    android中使用百度定位sdk实时的计算移动距离
    Android NDK开发常见错误
    cocos2dx中使用iconv转码(win32,iOS,Android)
    史上最全的CSS hack方式一览
    谈谈SQL 语句的优化技术
    PIVOT 和 UPIVOT 的使用(行转列)
    JQuery的Ajax跨域请求的解决方案
    64位windows2003 未在本地计算机上注册 microsoft.jet.oledb.4.0 提供程序
    httpModules 与 httpHandlers
    删除事件查看器中多余的日志分类
  • 原文地址:https://www.cnblogs.com/skylee03/p/7560032.html
Copyright © 2020-2023  润新知