• [BZOJ 3514]Codechef MARCH14 GERALD07加强版


    这题的做法很巧妙,我却写的很作死……

    今天算是狠狠的又补了一边 link-cut-tree ,完了又是发现自己很 SX 

    考虑已经有 i 条边构成的图,现在要加入第 i+1 跳边

    那么有两种情况:1.要么成环 2.要么不成环 (废话)

    我们认为成环的边是没有贡献的,不成环的边是有贡献的

    答案就是统计 l..r 条边中有贡献的边一共有几条,然后用 n 减一下

    我们再次定义第 i 条边加入后构成的环中最早被加入的边是 ntr[i] ,然后从第一条边起,每次在加入第 i 条边后,把第 ntr[i] 条边删除(233…)

    此时图始终呈一个生成森林

    那么 l..r 条边中有贡献的边的条数就是 l..r 条边中 ntr[i]<l 的边数

    因为 ntr[i]>=l 的说明这条边在加入后与 l..i 中的某条边构成了环,显然这是一条毫无贡献的边

    ntr 数组可以用 link-cut-tree 来解决,每次在 u 和 v 间连一条权为 w 的边等价于把 u 和 v 连向一个权值为 w 的点,我们就解决了化边权为点权的问题

    至于后面那个主席树就可以了……

    这真是一道可怕的数据结构题

      1 #include <cstdio>
      2 const int inf=0x7FFFFFFF;
      3 const int sizeOfPoint=200002;
      4 
      5 int n, m, k, type;
      6 int u[sizeOfPoint], v[sizeOfPoint];
      7 int time[sizeOfPoint<<1], ntr[sizeOfPoint];
      8 inline int getint();
      9 inline void putint(int);
     10 template<class type> inline void swap(type & a, type & b) {type t=a; a=b; b=t;}
     11 
     12 struct node
     13 {
     14     int id;
     15     node * min;
     16     bool rev;
     17     node * f, * c[2];
     18     inline node():id(0), rev(0) {min=this; f=c[0]=c[1]=this;}
     19     inline void maintain() {min=this; if (time[c[0]->min->id]<time[min->id]) min=c[0]->min; if (time[c[1]->min->id]<time[min->id]) min=c[1]->min;}
     20     inline void pushdown() {if (rev) swap(c[0], c[1]), c[0]->rev^=1, c[1]->rev^=1, rev=0;}
     21 };
     22 node * null=new node();
     23 node memoryOfLct[sizeOfPoint<<1], * portOfLct=memoryOfLct;
     24 node * t[sizeOfPoint<<1];
     25 inline node * newnode(int _id) {node * ret=portOfLct++; ret->id=_id; ret->min=ret; ret->rev=0; ret->f=ret->c[0]=ret->c[1]=null; return ret;}
     26 inline void rotate(node * x, int d) {node * y=x->f, * z=y->f; (y->c[d]=x->c[d^1])->f=y; (x->c[d^1]=y)->f=x; y->maintain(); if (z->c[0]==y) z->c[0]=x; if (z->c[1]==y) z->c[1]=x; x->f=z;}
     27 inline void splay(node * x)
     28 {
     29     node * y, * z; bool d, dd;
     30     x->pushdown();
     31     while ((y=x->f)!=null && (y->c[0]==x || y->c[1]==x))
     32         if ((z=y->f)!=null && (z->c[0]==y || z->c[1]==y))
     33         {
     34             z->pushdown(), y->pushdown(), x->pushdown();
     35             d=y->c[1]==x, dd=z->c[1]==y;
     36             if (d==dd) rotate(y, dd), rotate(x, d);
     37             else rotate(x, d), rotate(x, dd);
     38         }
     39         else
     40         {
     41             y->pushdown(), x->pushdown();
     42             d=y->c[1]==x;
     43             rotate(x, d);
     44         }
     45     x->maintain();
     46 }
     47 inline node * access(node * x) {node * y; for (y=null;x!=null;x=x->f) splay(x), x->c[1]=y, (y=x)->maintain(); return y;}
     48 inline void evert(node * x) {access(x)->rev^=1;}
     49 inline node * find(node * x) {for ( ;x->f!=null;x=x->f); return x;}
     50 inline void link(node * x, node * y) {evert(x); splay(x); x->f=y;}
     51 inline void cut(node * x, node * y) {evert(x); access(y); splay(y); y->c[0]=y->c[0]->f=null;}
     52 inline bool check(node * x, node * y) {return find(x)==find(y);}
     53 inline node * query(node * x, node * y) {evert(x); access(y); splay(y); return y->min;}
     54 
     55 struct seg {int cnt; seg * l, * r; inline seg():cnt(0) {l=r=this;}};
     56 seg * nul=new seg();
     57 seg memoryOfSeg[sizeOfPoint<<6], * portOfSeg=memoryOfSeg;
     58 seg * T[sizeOfPoint];
     59 inline seg * newseg(seg * t=nul) {seg * newt=portOfSeg++; if (t!=nul) newt->cnt=t->cnt, newt->l=t->l, newt->r=t->r; else newt->cnt=0, newt->l=nul, newt->r=nul; return newt;}
     60 seg * insert(seg * , int, int, int);
     61 
     62 inline void prepare();
     63 inline void build();
     64 inline int query(int, int);
     65 
     66 int main()
     67 {
     68     int lastans=0;
     69     int l, r;
     70 
     71     n=getint(); m=getint(); k=getint(); type=getint();
     72     for (int i=1;i<=m;i++) u[i]=getint(), v[i]=getint();
     73     prepare();
     74     build();
     75 
     76 
     77     for (int i=1;i<=k;i++)
     78     {
     79         l=getint(), r=getint();
     80         if (type) l^=lastans, r^=lastans;
     81         putint(lastans=query(l, r));
     82     }
     83 
     84     return 0;
     85 }
     86 inline int getint()
     87 {
     88     register int num=0;
     89     register char ch;
     90     do ch=getchar(); while (ch<'0' || ch>'9');
     91     do num=num*10+ch-'0', ch=getchar(); while (ch>='0' && ch<='9');
     92     return num;
     93 }
     94 inline void putint(int num)
     95 {
     96     char stack[10];
     97     register int top=0;
     98     if (num==0) stack[top=1]='0';
     99     for ( ;num;num/=10) stack[++top]=num%10+'0';
    100     for ( ;top;top--) putchar(stack[top]);
    101     putchar('
    ');
    102 }
    103 seg * insert(seg * t, int l, int r, int k)
    104 {
    105     seg * newt=newseg(t);
    106     newt->cnt++;
    107     if (l==r) return newt;
    108     int m=(l+r)>>1;
    109     if (k<=m) newt->l=insert(newt->l, l, m, k);
    110     else newt->r=insert(newt->r, m+1, r, k);
    111     return newt;
    112 }
    113 inline void prepare()
    114 {
    115     for (int i=1;i<=n;i++) t[i]=newnode(i);
    116     for (int i=0;i<=n;i++) time[i]=inf;
    117     for (int i=1, j=n+1;i<=m;i++, j++)
    118     {
    119         if (u[i]==v[i]) {ntr[i]=i; continue;}
    120         if (check(t[u[i]], t[v[i]]))
    121         {
    122             node * c=query(t[u[i]], t[v[i]]);
    123             ntr[i]=time[c->id];
    124             cut(t[u[i]], c); cut(t[v[i]], c);
    125         }
    126         t[j]=newnode(j); time[j]=i;
    127         link(t[u[i]], t[j]); link(t[v[i]], t[j]);
    128     }
    129 }
    130 inline void build()
    131 {
    132     T[0]=nul;
    133     for (int i=1;i<=m;i++)
    134         T[i]=insert(T[i-1], 0, m, ntr[i]);
    135 }
    136 inline int query(int x, int y)
    137 {
    138     seg * i=T[x-1], * j=T[y];
    139     int ret=0;
    140     int left=0, right=m, mid;
    141     for ( ;j!=nul; )
    142     {
    143         mid=(left+right)>>1;
    144         if (x>mid)
    145         {
    146             ret+=j->l->cnt-i->l->cnt;
    147             i=i->r, j=j->r;
    148             left=mid+1;
    149         }
    150         else
    151         {
    152             i=i->l, j=j->l;
    153             right=mid;
    154         }
    155     }
    156     return n-ret;
    157 }
    本傻莫名 T 出翔系列
  • 相关阅读:
    JAVA基础——异常详解
    Android Studio如何配置adb以及常用命令
    利用Android Studio编写 Android上的c与c++程序
    启动与销毁Activity
    应用资源概览
    Android 开发者文档 -- 应用基础知识
    51单片机最小系统
    同相放大器
    反相放大器
    面向对象开发C++快速入门视频教程 C++基础加实战视频教程
  • 原文地址:https://www.cnblogs.com/dyllalala/p/3980373.html
Copyright © 2020-2023  润新知