zoukankan      html  css  js  c++  java
  • UVaLive5031 Graph and Queries(时光倒流+名次树)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20332

    【思路】

           时光倒流+名次树(rank tree)。

           所谓“时光倒流”即逆向处理,因为D删除边并不好操作所以我们倒着处理,删除边转化为添加边,C转化为将weight变回操作前的数,Q不变。

           名次树实现以上操作:名次树是Treap+s域实现的,可以提供kth即查询第k大的数的操作和Treap的所有功能。

           1)对于D(x):合并from[x]与to[x]所在的rank tree,后序思想,将src中的结点逐个添加到dest中,采用启发式合并。

           2)对于Q(x,k):调用kth操作同时累计cnt与tot。

           3)对于C(x,v):调用一次romove(root[findset(x)],weight[x]),再调用一次insert(root[findset(x)],v)。

           用到一个并查集快速寻找x所属rank tree的根。

    【代码】

      1 #include<cstdio>
      2 #include<ctime>
      3 #include<cstring>
      4 #include<cstdlib>
      5 #include<vector>
      6 #include<iostream>
      7 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
      8 using namespace std;
      9 
     10 const int maxn = 120000+10;
     11 //Treap相关 
     12 struct Node{
     13     Node *ch[2];
     14     int r,v,s;    //r为优先级 v为键值 s为结点总数 
     15     Node(int w) :v(w) { ch[0]=ch[1]=NULL; s=1; r=rand(); }
     16     int cmp(int x) const{    //x应在左子树d=0 x应在右子树d=1 
     17         if(x==v) return -1;
     18         return x<v? 0:1;
     19     }
     20     int cmp2(int x) const{ return x<v? 0:1; }
     21     void maintain() {    //名次树维护 s
     22         s=1;
     23         if(ch[0]!=NULL) s+=ch[0]->s;
     24         if(ch[1]!=NULL) s+=ch[1]->s;
     25     }
     26 };
     27 void rotate(Node* &o,int d) {    //旋转操作 d=0左旋d=1右旋 
     28     Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o; 
     29     o->maintain();k->maintain(); o=k;
     30 }
     31 void insert(Node* &o,int x) {
     32     if(o==NULL)  o=new Node(x);
     33     else {
     34         int d=o->cmp2(x);        //可能会有键值相等的结点 
     35         insert(o->ch[d],x);
     36         if(o->ch[d]->r > o->r) rotate(o,d^1); //如果插入之后不满足堆的性质则反方向旋转
     37     }
     38     o->maintain();        //维护 
     39 }
     40 void remove(Node* &o,int x) {
     41     int d=o->cmp(x);
     42     if(d==-1) {
     43         Node *u=o;
     44         if(o->ch[0]!=NULL && o->ch[1]!=NULL){                            //根据左右子[优先级]旋转 旋转后递归删除x 
     45             int d2=o->ch[0]->r > o->ch[1]->r? 1:0;
     46             rotate(o,d2); remove(o->ch[d2],x);
     47         }
     48         else {
     49             if(o->ch[0]!=NULL) o=o->ch[0]; else o=o->ch[1];
     50             delete u;
     51         }
     52     }
     53     else 
     54         remove(o->ch[d],x);
     55     if(o!=NULL) o->maintain();
     56 }
     57 //名次树相关
     58 int kth(Node* o,int k) {    //返回第k[大]的数
     59     if(o==NULL || k<=0 || k>o->s) return 0;
     60     int s=o->ch[1]==NULL? 0:o->ch[1]->s;
     61     if(k==s+1) return o->v;
     62     else if(k<=s) return kth(o->ch[1],k);
     63     else return kth(o->ch[0],k-s-1); 
     64 }
     65 void mergeto(Node* &src,Node* &dest) {    //[后序遍历]合并两棵名次树 
     66     if(src->ch[0]!=NULL) mergeto(src->ch[0],dest);
     67     if(src->ch[1]!=NULL) mergeto(src->ch[1],dest);
     68     insert(dest,src->v);
     69     delete src;
     70     src=NULL;
     71 }
     72 void removetree(Node* &o) {    //[后序遍历]删除一棵名次树
     73     if(o->ch[0]!=NULL) removetree(o->ch[0]);
     74     if(o->ch[1]!=NULL) removetree(o->ch[1]);
     75     delete o;
     76     o=NULL;
     77 }
     78 //并查集相关
     79 int pa[maxn];
     80 int findset(int u) { return u==pa[u]? u:pa[u]=findset(pa[u]); }
     81 //题目相关
     82 Node* root[maxn];
     83 int weight[maxn],from[maxn],to[maxn];
     84 bool removed[maxn];
     85 int n,m,cnt,kase;
     86 long long sum;
     87 struct Command{  char type; int a,b;
     88 };
     89 vector<Command> cs;
     90 
     91 void addedge(int i) {
     92     int u=findset(from[i]),v=findset(to[i]);
     93     if(u!=v) {
     94         if(root[u]->s > root[v]->s) { pa[v]=u; mergeto(root[v],root[u]); }
     95         else { pa[u]=v; mergeto(root[u],root[v]); }
     96     }
     97 }
     98 void query(int x,int k) {
     99     cnt++;
    100     sum+=kth(root[findset(x)],k);
    101 }
    102 void changeWeight(int x,int p) {
    103     int u=findset(x);
    104     remove(root[u],weight[x]);
    105     insert(root[u],p);
    106     weight[x]=p;
    107 }
    108 
    109 int main() {
    110     srand(time(0));    //初始化随机数种子
    111     kase=0;
    112     while(scanf("%d%d",&n,&m)==2 && (n&&m)) {
    113         FOR(i,1,n) scanf("%d",&weight[i]);
    114         FOR(i,1,m) scanf("%d%d",&from[i],&to[i]);
    115         char type;
    116         memset(removed,0,sizeof(removed));
    117         cs.clear();
    118         while(scanf(" %c",&type)==1 && type!='E') {
    119             int x=0,p=0;
    120             scanf("%d",&x);
    121             if(type=='D') removed[x]=1;
    122             if(type=='Q')  scanf("%d",&p);
    123             if(type=='C') {
    124                 scanf("%d",&p);
    125                 swap(p,weight[x]);
    126             }
    127             cs.push_back((Command){type,x,p});
    128         }
    129         FOR(i,1,n) {
    130             pa[i]=i; if(root[i]!=NULL) removetree(root[i]);
    131             root[i]=new Node(weight[i]);
    132         }
    133         FOR(i,1,m) if(!removed[i]) addedge(i);
    134         int d=cs.size(); sum=cnt=0;
    135         for(int i=d-1;i>=0;i--) {
    136             if(cs[i].type=='D') addedge(cs[i].a);
    137             if(cs[i].type=='Q') query(cs[i].a,cs[i].b);
    138             if(cs[i].type=='C') changeWeight(cs[i].a,cs[i].b);
    139         }
    140         printf("Case %d: %.6lf
    ",++kase,sum/(double)cnt);
    141     }
    142     return 0;
    143 }
  • 相关阅读:
    Java基础知识➣面向对象(八)
    Linux(CentOS7)安装Tomcat
    Java基础知识➣发送Emai和访问MySQL数据库(七)
    Java基础知识➣网络Socket(六)
    JS 的点点滴滴
    git 快速入门(二)
    zxing 生成二维码
    js生成二维码
    Markdown简介
    java常用string inputStream转换
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5010295.html
Copyright © 2011-2022 走看看