将删边改为插边,如果是无向图直接线段树合并即可,考虑如何将有向边转换为无向边

令$t_{i}$表示当插入到第$t_{i}$条边时恰好满足$x_{i}$与$y_{i}$在同一个强连通分量中,然后分类讨论:

1.$t_{i}<i$或$t_{i}$不存在,这条边无意义,删去;

2.$t_{i}\ge i$,将所有这类边按照$t_{i}$排序,之后视作无向边进行操作即可

考虑如何求出$t_{i}$,整体二分,对于当前区间$[l,r]$,问题即如何求出时间在$[1,mid]$中所有边所构成的强连通分量

我们将$[1,mid]$中的边分为两类:1.答案(不等同于时间)小于$l$;2.答案在$[l,r]$中

第一类边对图的贡献仅仅只是强连通分量,即第一类边构成的图恰好是若干个强连通分量(否则就答案就不会小于$l$),因此用按秩合并并查集来维护强连通分量(要支持撤销)

第二类边的数量即当前询问区间,可以暴力加入再求tarjan(只能搜有新边的点,这样复杂度可以保证)

假设$n,m,q$同阶,总复杂度为$o(n\log_{2}n)$(并查集的$log_{n}$应该与整体二分和线段树合并独立)

  1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 100005
4 #define ll long long
5 #define mid (l+r>>1)
6 struct ji{
7 int t,x,y;
8 }a[N<<1],e[N<<1],ee[N<<1];
9 struct ji2{
10 int nex,to;
11 }edge[N<<1];
12 vector<int>vv,v[N<<1];
13 vector<pair<int,int> >re;
14 map<int,int>mat[N];
15 int V,E,n,m,q,p,x,y,head[N],vis[N],dfn[N],low[N],st[N],fa[N],sz[N],w[N],r[N],ls[N*100],rs[N*100],f[N*100];
16 ll ans[N<<1],sum[N*100];
17 bool cmp(ji x,ji y){
18 return x.t<y.t;
19 }
20 int find(int k){
21 if (k==fa[k])return k;
22 return find(fa[k]);
23 }
24 void add(int x,int y){
25 edge[E].nex=head[x];
26 edge[E].to=y;
27 head[x]=E++;
28 }
29 void merge1(int x,int y){
30 x=find(x);
31 y=find(y);
32 if (x!=y){
33 if (sz[x]>sz[y])swap(x,y);
34 fa[x]=y;
35 sz[y]+=sz[x];
36 re.push_back(make_pair(x,y));
37 }
38 }
39 void dfs(int k){
40 vis[k]=1;
41 dfn[k]=low[k]=++dfn[0];
42 st[++st[0]]=k;
43 for(int i=head[k];i!=-1;i=edge[i].nex)
44 if (!dfn[edge[i].to]){
45 dfs(edge[i].to);
46 low[k]=min(low[k],low[edge[i].to]);
47 }
48 else
49 if (vis[edge[i].to])low[k]=min(low[k],dfn[edge[i].to]);
50 if (dfn[k]==low[k]){
51 int las=st[st[0]--];
52 vis[las]=0;
53 while (las!=k){
54 vis[st[st[0]]]=0;
55 merge1(st[st[0]],las);
56 las=st[st[0]--];
57 }
58 }
59 }
60 void dfs(int l,int r,int x,int y){
61 if (x>y)return;
62 if (l==r){
63 for(int i=x;i<=y;i++)
64 if ((l<q)||(find(e[i].x)==find(e[i].y)))v[q-l+1].push_back(mat[e[i].x][e[i].y]);
65 return;
66 }
67 vv.clear();
68 for(int i=x;i<=y;i++){
69 if (e[i].t>mid)continue;
70 int x=find(e[i].x),y=find(e[i].y);
71 vv.push_back(x);
72 if (x!=y){
73 vv.push_back(y);
74 add(x,y);
75 }
76 }
77 int sre=re.size();
78 for(int i=0;i<vv.size();i++)
79 if (!dfn[vv[i]])dfs(vv[i]);
80 E=dfn[0]=0;
81 for(int i=0;i<vv.size();i++){
82 head[vv[i]]=-1;
83 dfn[vv[i]]=0;
84 }
85 vv.clear();
86 for(int i=x;i<=y;i++)
87 if ((e[i].t<=mid)&&(find(e[i].x)==find(e[i].y)))vv.push_back(i);
88 for(int i=x,j=vv.size();i<x+vv.size();i++)
89 if ((e[i].t>mid)||(find(e[i].x)!=find(e[i].y)))swap(e[i],e[vv[--j]]);
90 int svv=vv.size();
91 dfs(mid+1,r,x+svv,y);
92 while (re.size()>sre){
93 sz[re[re.size()-1].second]-=sz[re[re.size()-1].first];
94 fa[re[re.size()-1].first]=re[re.size()-1].first;
95 re.pop_back();
96 }
97 dfs(l,mid,x,x+svv-1);
98 }
99 void update(int &k,int l,int r,int x,int y){
100 if (!x)return;
101 if (!k)k=++V;
102 f[k]+=y;
103 sum[k]+=x*y;
104 if (l==r)return;
105 if (x<=mid)update(ls[k],l,mid,x,y);
106 else update(rs[k],mid+1,r,x,y);
107 }
108 long long query(int k,int l,int r,int x){
109 if (l==r)return min(x,f[k])*l;
110 if (x<=f[rs[k]])return query(rs[k],mid+1,r,x);
111 return sum[rs[k]]+query(ls[k],l,mid,x-f[rs[k]]);
112 }
113 int merge(int k1,int k2){
114 if ((!k1)||(!k2))return k1+k2;
115 if ((!ls[k1])&&(!rs[k1])){
116 f[k1]+=f[k2];
117 sum[k1]+=sum[k2];
118 return k1;
119 }
120 ls[k1]=merge(ls[k1],ls[k2]);
121 rs[k1]=merge(rs[k1],rs[k2]);
122 f[k1]=f[ls[k1]]+f[rs[k1]];
123 sum[k1]=sum[ls[k1]]+sum[rs[k1]];
124 return k1;
125 }
126 void merge2(int x,int y){
127 x=find(x);
128 y=find(y);
129 if (x!=y){
130 if (sz[x]>sz[y])swap(x,y);
131 fa[x]=y;
132 sz[y]+=sz[x];
133 r[y]=merge(r[x],r[y]);
134 }
135 }
136 int main(){
137 scanf("%d%d%d",&n,&m,&q);
138 for(int i=1;i<=n;i++)scanf("%d",&w[i]);
139 memset(head,-1,sizeof(head));
140 for(int i=1;i<=m;i++){
141 scanf("%d%d",&e[i].x,&e[i].y);
142 e[i].t=1;//t表示插入的时间
143 mat[e[i].x][e[i].y]=i;
144 }
145 for(int i=1;i<=q;i++){
146 scanf("%d%d%d",&p,&x,&y);
147 if (p==1)e[mat[x][y]].t=q-i+1;
148 if (p==2)w[x]+=y;
149 a[i]=ji{p,x,y};
150 }
151 sort(e+1,e+m+1,cmp);
152 memcpy(ee,e,sizeof(ee));
153 for(int i=1;i<=m;i++)mat[e[i].x][e[i].y]=i;
154 for(int i=1;i<=n;i++){
155 fa[i]=i;
156 sz[i]=1;
157 }
158 dfs(1,q,1,m);
159 for(int i=1;i<=n;i++){
160 fa[i]=i;
161 sz[i]=1;
162 update(r[i],0,1e9,w[i],1);
163 }
164 for(int i=m;i;i--){
165 for(int j=0;j<v[i].size();j++)merge2(ee[v[i][j]].x,ee[v[i][j]].y);
166 if (a[i].t==3)ans[++ans[0]]=query(r[find(a[i].x)],0,1e9,a[i].y);
167 if (a[i].t==2){
168 update(r[find(a[i].x)],0,1e9,w[a[i].x],-1);
169 w[a[i].x]-=a[i].y;
170 update(r[find(a[i].x)],0,1e9,w[a[i].x],1);
171 }
172 }
173 for(int i=ans[0];i;i--)printf("%lld\n",ans[i]);
174 }

[luogu5163]WD与地图的更多相关文章

  1. WD与地图 解题报告

    WD与地图 哎,我好傻啊,看了题解还弄错了一遍,靠着lbw指点才董 题意:给一个带点权有向图,要求支持删边,查询一个scc前\(k\)大权值,修改点权,不强制在线. 显然倒序处理变成加边 考虑求出每条 ...

  2. 【LUOGU???】WD与地图 整体二分 线段树合并

    题目大意 有一个简单有向图.每个点有点权. 有三种操作: 修改点权 删除一条边 询问和某个点在同一个强连通分量中的点的前 \(k\) 大点权和. \(n\leq 100000,m,q\leq 2000 ...

  3. 洛谷P5163 WD与地图

    只有洛谷的毒瘤才会在毒瘤月赛里出毒瘤题...... 题意:三个操作,删边,改变点权,求点x所在强连通分量内前k大点权之和. 解:狗屎毒瘤数据结构乱堆...... 整体二分套(tarjan+并查集) + ...

  4. P5163 WD与地图(整体二分+权值线段树)

    传送门 细节要人命.jpg 这题思路太新奇了--首先不难发现可以倒着做变成加边,但是它还需要我们资瓷加边的同时维护强连通分量.显然加边之后暴力跑是不行的 然后有一个想法,对于一条边\((u,v)\), ...

  5. P5163 WD与地图 [整体二分,强连通分量,线段树合并]

    首先不用说,倒着操作.整体二分来做强连通分量,然后线段树合并,这题就做完了. // powered by c++11 // by Isaunoya #include <bits/stdc++.h ...

  6. 题解 洛谷 P5163 【WD与地图】

    首先将操作倒序,把删边转化为加边.先考虑若边是无向边,条件为连通,要怎么处理. 可以用并查集来维护连通性,对每个连通块维护一颗权值线段树,连通块的合并用线段树合并来实现,线段树同时也支持了修改点权. ...

  7. 使用R画地图数据

    用R画地图数据 首先,从这里下载中国地图的GIS数据,这是一个压缩包,完全解压后包含三个文件(bou2_4p.dbf.bou2_4p.shp和bou2_4p.shx),将这三个文件解压到同一个目录下. ...

  8. iOS地图

    地图 1.主要用到了地图展示和定位功能 CoreLocation框架的使用: 导入头文件        #import <CoreLocation/CoreLocation.h>CoreL ...

  9. Android百度地图附加搜索和公交路线方案搜索

    合肥程序员群:49313181.    合肥实名程序员群:128131462 (不愿透露姓名和信息者勿加入) Q  Q:408365330     E-Mail:egojit@qq.com 综述: 今 ...

随机推荐

  1. 如何用redis统计海量UV?

    前言 我们先思考一个常见的业务问题:如果你负责开发维护一个大型的网站,有一天老板找产品经理要网站每个网页每天的 UV 数据,然后让你来开发这个统计模块,你会如何实现? 统计uv的常用方法以及优缺点 其 ...

  2. 技术番外篇丨Github Action CI/CD

    起源 看到.Net群里再聊CI/CD,我就这里分享一下我目前自己一些小东西的做法,我目前在Github有一个自己私有的组织,里面存放了我的部分商业化项目,早期我采用Jenkins用Webhooks进行 ...

  3. CentOS7部署Prometheus

    部署Prometheus监控报警系统 一.Prometheus介绍 Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库(TSDB):Prometheus使用Go语言开发, ...

  4. 告别Vuex,发挥compositionAPI的优势,打造Vue3专用的轻量级状态

    Vuex 的遗憾 Vuex 是基于 Vue2 的 option API 设计的,因为 optionAPI 的一些先天问题,所以导致 Vuex 不得不用各种方式来补救,于是就出现了 getter.mut ...

  5. 第3次 Beta Scrum Meeting

    本次会议为Beta阶段第3次Scrum Meeting会议 会议概要 会议时间:2021年6月2日 会议地点:「腾讯会议」线上进行 会议时长:0.5小时 会议内容简介:对完成工作进行阶段性汇报:对下一 ...

  6. 零基础入门之Linux进程基础

    计算机实际上可以做的事情实质上非常简单,比如计算两个数的和,再比如在内存中寻找到某个地址等等.这些最基础的计算机动作被称为指令(instruction).所谓的程序(program),就是这样一系列指 ...

  7. TT模板的作用及使用

    一.假如你在ef中添加一个实体,没有模板,你需要在DAL层中新建一个"莫某Dal"和"I某某Dal"以及在公共的DbSession中加你的这个dal,然后需要在 ...

  8. Android上安装第三方库

    在Android sdk中安装预安装第三方的(动态,静态)库,到系统中,方便模块无差别的使用. Android.mk include $(CLEAR_VARS) LOCAL_MODULE_TAGS : ...

  9. 51nod_1006 最长公共子序列,输出路径【DP】

    题意: 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca也是,其中abca是这两个 ...

  10. linux 文件描述符和inode 的理解和区别

    inode 或i节点是指对文件的索引.如一个系统,所有文件是放在磁盘或flash上,就要编个目录来说明每个文件在什么地方,有什么属性,及大小等.就像书本的目录一样,便于查找和管理.这目录是操作系统需要 ...