• bzoj3514 Codechef MARCH14 GERALD07加强版


    传送门

    各种脑残错误调了半个下午+晚上半小时……先是把最大生成树写成了最小生成树,然后是初始化的值忘了改,最后还把主席树写挂了……这人没救了

    我说那个PE只是我好奇为什么只有一个PE才故意去试的你信么……

    言归正传……

    这题是在ysq的博客上看见的,看完题解之后我的感想就是:妙,妙啊……(感觉一道思路好题就这样变成无脑练码力的题了……说的跟你能自己想出来似的

    还是写个详细点的题解吧……

    (约定提到的最小/大均为以编号为关键字)

    对于每个询问的区间,我们可以只取出区间中所有边组成的最小生成森林,显然这样做对答案是没有影响的,因此我们的任务就变成了在线询问某个区间中所有边组成的最小生成森林的边数。注意这里的区间同时也是权值区间,这给我们带来了一些特殊性质。

    考虑逆序添加所有边并动态维护最小生成树,但这样似乎没法得到关于某个区间中所有边组成的最小生成森林的什么信息,除非你搞一个可持久化LCT+块状链表出来,但显然这是不可能的……

    因此考虑正序添加所有边并动态维护最大生成树,那么可以分类讨论一下:

    边的两端不连通:显然所有包括它的区间的最小生成森林中都会有它(因为它是所有连接两个连通块的边中权值最小的那一个)。

    边的两端连通:加入这条边后会形成一个环,这时一定会删除环上最早加入的那条边(因为维护的是最大生成树),记被删除的边编号为id,那么所有包含当前边且左端点>id的区间的最小生成森林中都会有当前边,而其他区间的最小生成森林中都不会有这条边(左端点≤id的区间中id号边还存在,由最小生成森林的定义可知应由id号边代替当前边;不包含当前边的区间的最小生成森林里怎么可能会有这条边……)。

    如果定义边的两端不连通时被删除边的编号为0,那么问题就变成了每次询问区间[l,r]中因加入这条边而被删除的边的编号<l的边数(好像有点绕……)。显然这是主席树模板题,主席树裸上即可。

    到这里我们的做法也就呼之欲出了:正序把所有边加进来,用LCT维护最大生成树并记录每条边删掉的边的编号(没删掉则为0),最后用主席树在线回答每个询问,复杂度O((n+m)logn)。

      1 /**************************************************************
      2     Problem: 3514
      3     User: hzoier
      4     Language: C++
      5     Result: Accepted
      6     Time:33584 ms
      7     Memory:93752 kb
      8 ****************************************************************/
      9 #include<cstdio>
     10 #include<cstring>
     11 #include<algorithm>
     12 #include<map>
     13 #define isroot(x) ((x)->p==null||((x)->p->ch[0]!=(x)&&(x)->p->ch[1]!=(x)))
     14 #define dir(x) ((x)==(x)->p->ch[1])
     15 using namespace std;
     16 const int maxn=200010;
     17 struct node{
     18     int key,mn,pos;
     19     bool rev;
     20     node *ch[2],*p;
     21     node(int key=(~0u)>>1):key(key),mn(key),pos(-1),rev(false){}
     22     inline void pushdown(){
     23         if(!rev)return;
     24         ch[0]->rev^=true;
     25         ch[1]->rev^=true;
     26         swap(ch[0],ch[1]);
     27         if(pos!=-1)pos^=1;
     28         rev=false;
     29     }
     30     inline void refresh(){
     31         mn=key;
     32         pos=-1;
     33         if(ch[0]->mn<mn){
     34             mn=ch[0]->mn;
     35             pos=0;
     36         }
     37         if(ch[1]->mn<mn){
     38             mn=ch[1]->mn;
     39             pos=1;
     40         }
     41     }
     42 }null[maxn<<1],*ptr=null;
     43 node *newnode(int);
     44 node *access(node*);
     45 void makeroot(node*);
     46 void link(node*,node*);
     47 void cut(node*,node*);
     48 node *getroot(node*);
     49 node *getmin(node*,node*);
     50 void splay(node*);
     51 void rot(node*,int);
     52 void build(int,int,int&,int);
     53 void query(int,int,int,int);
     54 int sm[maxn<<5]={0},lc[maxn<<5]={0},rc[maxn<<5]={0},root[maxn]={0},cnt=0;
     55 map<node*,pair<node*,node*> >mp;
     56 node *tmp;
     57 int n,m,q,tp,x,y,k,l,r,t,ans=0;
     58 int main(){
     59     null->ch[0]=null->ch[1]=null->p=null;
     60     scanf("%d%d%d%d",&n,&m,&q,&tp);
     61     for(int i=1;i<=n;i++)newnode((~0u)>>1);
     62     for(int i=1;i<=m;i++){
     63         scanf("%d%d",&x,&y);
     64         if(x==y){
     65             root[i]=root[i-1];
     66             continue;
     67         }
     68         if(getroot(null+x)!=getroot(null+y)){
     69             tmp=newnode(i);
     70             k=0;
     71         }
     72         else{
     73             tmp=getmin(null+x,null+y);
     74             cut(tmp,mp[tmp].first);
     75             cut(tmp,mp[tmp].second);
     76             k=tmp->key;
     77             tmp->key=i;
     78             tmp->refresh();
     79         }
     80         link(tmp,null+x);
     81         link(tmp,null+y);
     82         mp[tmp]=make_pair(null+x,null+y);
     83         build(0,m-1,root[i],root[i-1]);
     84     }
     85     while(q--){
     86         scanf("%d%d",&l,&r);
     87         if(tp){
     88             l^=ans;
     89             r^=ans;
     90         }
     91         ans=n;
     92         t=--l;
     93         query(0,m-1,root[r],root[l]);
     94         printf("%d
    ",ans);
     95     }
     96     return 0;
     97 }
     98 node *newnode(int x){
     99     *++ptr=node(x);
    100     ptr->ch[0]=ptr->ch[1]=ptr->p=null;
    101     return ptr;
    102 }
    103 node *access(node *x){
    104     node *y=null;
    105     while(x!=null){
    106         splay(x);
    107         x->ch[1]=y;
    108         (y=x)->refresh();
    109         x=x->p;
    110     }
    111     return y;
    112 }
    113 void makeroot(node *x){
    114     access(x);
    115     splay(x);
    116     x->rev^=true;
    117 }
    118 void link(node *x,node *y){
    119     makeroot(x);
    120     x->p=y;
    121 }
    122 void cut(node *x,node *y){
    123     makeroot(x);
    124     access(y);
    125     splay(y);
    126     y->ch[0]->p=null;
    127     y->ch[0]=null;
    128     y->refresh();
    129 }
    130 node *getroot(node *x){
    131     x=access(x);
    132     while(x->pushdown(),x->ch[0]!=null)x=x->ch[0];
    133     splay(x);
    134     return x;
    135 }
    136 node *getmin(node *x,node *y){
    137     makeroot(x);
    138     x=access(y);
    139     while(x->pushdown(),x->pos!=-1)x=x->ch[x->pos];
    140     splay(x);
    141     return x;
    142 }
    143 void splay(node *x){
    144     x->pushdown();
    145     while(!isroot(x)){
    146         if(!isroot(x->p))x->p->p->pushdown();
    147         x->p->pushdown();
    148         x->pushdown();
    149         if(isroot(x->p)){
    150             rot(x->p,dir(x)^1);
    151             break;
    152         }
    153         if(dir(x)==dir(x->p))rot(x->p->p,dir(x->p)^1);
    154         else rot(x->p,dir(x)^1);
    155         rot(x->p,dir(x)^1);
    156     }
    157 }
    158 void rot(node *x,int d){
    159     node *y=x->ch[d^1];
    160     if((x->ch[d^1]=y->ch[d])!=null)y->ch[d]->p=x;
    161     y->p=x->p;
    162     if(!isroot(x))x->p->ch[dir(x)]=y;
    163     (y->ch[d]=x)->p=y;
    164     x->refresh();
    165     y->refresh();
    166 }
    167 void build(int l,int r,int &rt,int pr){
    168     sm[rt=++cnt]=sm[pr]+1;
    169     if(l==r)return;
    170     lc[rt]=lc[pr];
    171     rc[rt]=rc[pr];
    172     int mid=(l+r)>>1;
    173     if(k<=mid)build(l,mid,lc[rt],lc[pr]);
    174     else build(mid+1,r,rc[rt],rc[pr]);
    175 }
    176 void query(int l,int r,int rt,int pr){
    177     if(!rt&&!pr)return;
    178     if(t>=r){
    179         ans-=sm[rt]-sm[pr];
    180         return;
    181     }
    182     int mid=(l+r)>>1;
    183     query(l,mid,lc[rt],lc[pr]);
    184     if(t>mid)query(mid+1,r,rc[rt],rc[pr]);
    185 }
    186 /*
    187 如果是离线的话,我们可以LCT+莫队什么的乱搞是吧,但是在线就……
    188 不过还是有一个很喵的做法——
    189 我们用LCT维护一棵生成树,当加入一条边i的时候(i是其编号),其连接的两个点可能已经联通,加入i之后会形成一个环,我们弹掉这个环上编号最小的边(也就是加入最早的边),并记录其编号为ntr_i。特殊的,如果i没有弹掉任何边,我们记ntr_i=0。
    190 对于一个询问[L,R](表示我们只保留e|e∈[L,R]),答案就是$n?sum_{i=L}^R(ntr_i<L)$。这个就是主席树了。
    191 ——YouSiki
    192  
    193 这做法简直是妙啊……
    194 */
    View Code

    再%一发ysq,妙,妙啊……

  • 相关阅读:
    Tensorflow API解读
    《deep learning book》-- 引言
    算法导论--第一部分(基础知识)
    leetcode解题笔记--part1--array
    TensorFlow实战--阅读笔记part4
    TensorFlow实战--阅读笔记part3
    Pro Git阅读笔记--part1
    TensorFlow实战--阅读笔记part2
    周长最长分析
    VC维含义的个人理解
  • 原文地址:https://www.cnblogs.com/hzoier/p/6411336.html
Copyright © 2020-2023  润新知