hdu 3726 Graph and Queries(splay查询第k大,启发式合并,删除操作)

题目链接:hdu 3726 Graph and Queries

题意:

最开始给你n个点,每个点最开始有一个权值,并且都是独立的,现在给你m条边,表示对应的两个点是连接的。

现在有三种操作:

Q x k,表示询问与x这个点联通的所有点中第k大的权值。

D x,表示删除第x条边。

C x y,表示改变x点的权值为y。

题解:

如果正着来做肯定比较麻烦,不好维护。

一看输出,可以离线处理,那么我们就倒着搞。

把所有的询问和边,点的变化全部存起来,然后用splay来维护。

每次删除就是倒着的合并,合并采用启发式合并,多个log而已。

最后注意的是查询第k大,这里的k可能为负,这里我T了2天。- -!

  1 #include<bits/stdc++.h>
  2 #define F(i,a,b) for(int i=a;i<=b;++i)
  3 using namespace std;
  4 typedef pair<int,int>P;
  5
  6 const int N=2e6+7;
  7 int _t,a[N];
  8 struct tree//键值可重,去重需要加num记录这个数的个数
  9 {
 10     int key,sz,f,ch[2];
 11     int add,rev;
 12 }T[N];
 13
 14 struct Splay_tree
 15 {
 16     int root;
 17     void init(){root=0;}
 18     inline void nw(int &x,int key,int f)
 19     {
 20         T[++_t].key=key,T[_t].f=f,T[_t].sz=1;
 21         T[_t].ch[0]=T[_t].ch[1]=0,x=_t;
 22         T[_t].add=T[_t].rev=0;
 23     }
 24     inline void up(int x){T[x].sz=T[T[x].ch[0]].sz+T[T[x].ch[1]].sz+1;}
 25     void rotate(int x){
 26         int y=T[x].f,w=T[y].ch[1]==x;
 27         T[y].ch[w]=T[x].ch[w^1];
 28         if(T[x].ch[w^1])T[T[x].ch[w^1]].f=y;
 29         if(T[y].f){
 30             int z=T[y].f;
 31             if(T[z].ch[0]==y)T[z].ch[0]=x;
 32             if(T[z].ch[1]==y)T[z].ch[1]=x;
 33         }
 34         T[x].f=T[y].f,T[x].ch[w^1]=y,T[y].f=x;up(y);
 35     }
 36
 37     void splay(int x,int w){
 38         int s=1,i=x,y;a[1]=x;
 39         while(T[x].f!=w){
 40             y=T[x].f;
 41             if(T[y].f!=w)(T[T[y].f].ch[0]==y)^(T[y].ch[0]==x)?rotate(x):rotate(y);
 42             rotate(x);
 43         }
 44         if(!w)root=x;
 45         up(x);
 46     }
 47     inline int find(int key) //返回值为key的节点 若无返回0 若有将其转移到根处
 48     {
 49         if(!root)return 0;
 50         int x=root;
 51         for(;x&&T[x].key!=key;)x=T[x].ch[T[x].key<key];
 52         if(x)splay(x,0);
 53         return x;
 54     }
 55     inline void ins(int key)//插入key键值
 56     {
 57         if(!root){nw(root,key,0);return;}
 58         int x=root,y=0;
 59         while(x)y=x,T[x].sz++,x=T[x].ch[T[x].key<key];
 60         nw(T[y].ch[T[y].key<key],key,y);
 61         splay(T[y].ch[T[y].key<key],0);
 62     }
 63     inline void det(int key)//删除值为key的节点1个
 64     {
 65         int x=find(key);
 66         if(!x)return;
 67         int y=T[x].ch[0],z=T[x].ch[1];
 68         while(T[y].ch[1])y=T[y].ch[1];
 69         while(T[z].ch[0])z=T[z].ch[0];
 70         if(!y&&!z)root=0;
 71         else if(!y)splay(z,0),T[z].ch[0]=0,up(z);
 72         else if(!z)splay(y,0),T[y].ch[1]=0,up(y);
 73         else splay(y,0),splay(z,y),T[z].ch[0]=0,up(z),up(y);
 74     }
 75     inline int kth(int k)//获得第k小的键值
 76     {
 77         if(k>T[root].sz||k<=0)return 0;
 78         k=T[root].sz-k+1;
 79         int x=root,tmp;
 80         while(1)
 81         {
 82             tmp=T[T[x].ch[0]].sz+1;
 83             if(k==tmp)break;
 84             if(k<tmp)x=T[x].ch[0];else k-=tmp,x=T[x].ch[1];
 85         }
 86         return T[x].key;
 87     }
 88 }spt[N];
 89 //--------------------------------
 90 int n,m,g[N],w[N],nxt[N],ed,x,vis[N],f[N],qed,cas;
 91 P edge[N];
 92
 93 struct query
 94 {
 95     char cmd[2];
 96     int x,y;
 97 }q[N];
 98
 99 void init(){_t=ed=0;F(i,1,n)spt[i].init(),f[i]=i,g[i]=0;}
100 void adg(int x,int c){w[++ed]=c,nxt[ed]=g[x],g[x]=ed;}
101 int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
102
103 void dfs(int r,int x)
104 {
105     if(!r)return;
106     spt[x].ins(T[r].key);
107     dfs(T[r].ch[0],x),dfs(T[r].ch[1],x);
108 }
109
110 void merge(int x,int y)
111 {
112     int fx=find(x),fy=find(y);
113     if(fx==fy)return;
114     if(T[spt[fx].root].sz<T[spt[fy].root].sz)swap(fx,fy);
115     dfs(spt[fy].root,fx),f[fy]=fx;
116 }
117
118 int main()
119 {
120     while(~scanf("%d%d",&n,&m),n+m)
121     {
122         init();
123         F(i,1,n)scanf("%d",&x),adg(i,x);
124         F(i,1,m)scanf("%d%d",&edge[i].first,&edge[i].second),vis[i]=0;
125         for(qed=0;;)
126         {
127             scanf("%s",q[++qed].cmd);
128             if(q[qed].cmd[0]==‘E‘)break;
129             else if(q[qed].cmd[0]==‘D‘)scanf("%d%d",&q[qed].x),vis[q[qed].x]=1;
130             else if(q[qed].cmd[0]==‘Q‘)scanf("%d%d",&q[qed].x,&q[qed].y);
131             else scanf("%d%d",&q[qed].x,&q[qed].y),adg(q[qed].x,q[qed].y);
132         }
133         F(i,1,n)spt[i].ins(w[g[i]]);
134         F(i,1,m)if(!vis[i])merge(edge[i].first,edge[i].second);
135         double ans=0;int cnt=0;
136         for(int i=qed-1;i>0;i--)
137         {
138             if(q[i].cmd[0]==‘Q‘)
139             {
140                 cnt++;
141                 int fx=find(q[i].x);
142                 ans+=spt[fx].kth(q[i].y);
143             }else if(q[i].cmd[0]==‘D‘)merge(edge[q[i].x].first,edge[q[i].x].second);
144             else
145             {
146                 int fx=find(q[i].x);
147                 spt[fx].det(w[g[q[i].x]]);
148                 g[q[i].x]=nxt[g[q[i].x]];
149                 spt[fx].ins(w[g[q[i].x]]);
150             }
151         }
152         printf("Case %d: %.6f\n",++cas,ans/cnt);
153     }
154     return 0;
155 }

时间: 2024-10-13 12:17:01

hdu 3726 Graph and Queries(splay查询第k大,启发式合并,删除操作)的相关文章

HDU 3726 Graph and Queries treap树

题目来源:HDU 3726 Graph and Queries 题意:见白书 思路:刚学treap 參考白皮书 #include <cstdio> #include <cstring> #include <cstdlib> using namespace std; struct Node { Node *ch[2]; int r; int v; int s; Node(int v): v(v) { ch[0] = ch[1] = NULL; r = rand(); s

HDU 3726 Graph and Queries Treap

这是一个比较全面的题,涉及到了添加删除寻找第k大还有树的合并. 做法大概先执行所有的删边操作,建立最终的图,这里可以用并查集维护一下, 方便判断是不是在一个联通块中,然后对每个子块建立一个Treap,如果遇到添加边导致两个联通块合并成一个的情况,就将两棵树当中小的那个合并到大的那个里面.因为每次这样的合并操作,必然会有小的那个大小翻倍,其实复杂度是科学的,所以合并操作只要很裸很裸的一个一个节点插入就好. 这题有点考验代码能力,写起来比较的麻烦. #include <cstdio> #inclu

PAT天梯赛练习题 L3-002. 堆栈(线段树查询第K大值)

L3-002. 堆栈 时间限制 200 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 大家都知道“堆栈”是一种“先进后出”的线性结构,基本操作有“入栈”(将新元素插入栈顶)和“出栈”(将栈顶元素的值返回并从堆栈中将其删除).现请你实现一种特殊的堆栈,它多了一种操作叫“查中值”,即返回堆栈中所有元素的中值.对于N个元素,若N是偶数,则中值定义为第N/2个最小元:若N是奇数,则中值定义为第(N+1)/2个最小元. 输入格式: 输入第一行给出正整

【HDOJ】3726 Graph and Queries

Treap的基础题目,Treap是个挺不错的数据结构. 1 /* */ 2 #include <iostream> 3 #include <string> 4 #include <map> 5 #include <queue> 6 #include <set> 7 #include <stack> 8 #include <vector> 9 #include <deque> 10 #include <al

HDU 5249 离线树状数组求第k大+离散化

KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1160    Accepted Submission(s): 488 Problem Description 你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度.数十亿的请求被推到一个大管道后同时服务从管头拉取请求.让我们来定义每个请求都有一个重要值.我的

Entity Framework学习三:查询、插入、更新和删除操作

1.LINQ过滤数据  var query = from person in context.People where person.FirstName.StartsWith("a") select person; var methodQuery = context.People.Where(p => p.FirstName.StartsWith("a")); 两种不同的写法,效果一样. 多条件组合查找 var query = from person in c

HDU 3397 Sequence operation(线段树&#183;成段更新&#183;区间合并&#183;混合操作)

题意  给你一个只有0, 1的数组  有这些操作 0. 将[a, b]区间的所有数都改为0 1. 将[a, b]区间的所有数都改为1 2. 将[a, b]区间的所有数都取反 即与1异或 3. 输出区间[a, b]中1的个数  即所有数的和 4. 输出区间[a, b]中最大连续1的长度 对于所有的3, 4操作输出对应的答案 单个的操作都很简单  但搞在一起就有点恶心了  还好数组里的数只有0和1 线段树维护9个值 对应区间0, 1的最大长度len[i]  对应区间左端点为起点的最大0, 1长度ll

UVaLive 5031 Graph and Queries (Treap)

Graph and Queries Description You are given an undirected graph with N vertexes and M edges. Every vertex in this graph has an integer value assigned to it at the beginning. You’re also given a sequence of operations and you need to process them as r

HDU 4006 The kth great number(优先队列&#183;第K大数)

题意  动态查询第K大的数 用小数在前优先队列维护K个数  每要插入一个数时 若这个数小于队首元素那么就不用插入了  否则队首元素出队  这个数入队  每次询问只用输出队首元素就行了 #include<cstdio> #include<queue> using namespace std; int main() { int n, a, k; char op[5]; while(~scanf("%d%d", &n, &k)) { priority_