只有洛谷的毒瘤才会在毒瘤月赛里出毒瘤题......

题意:三个操作,删边,改变点权,求点x所在强连通分量内前k大点权之和。

解:狗屎毒瘤数据结构乱堆......

整体二分套(tarjan+并查集) + 线段树合并。

首先可以变成加边。

然后就是神奇操作让人难以置信......

对于每条边,我们有个时刻t使得它的两端点在同一scc内。那么如何求出这个t呢?

整体二分!...这又是怎么想到的啊......

对于一个时刻mid,我们把小于它的边提取出来缩点,如果有的边两端点在一个scc,那么它的t就不大于mid。否则大于mid。

为了保证整体二分的复杂度,我们每次操作tarjan的图不能太大。具体来说,把之前做过的区间的scc用并查集缩起来。

对于每条边,提取两端点所在scc的代表元为关键点,构出虚图(?????),然后tarjan。

之后递归左边,之后并查集缩点,之后递归右边。

所有t求出之后,再倒着跑一遍询问,按照时刻把边的两端点在并查集中合并(表示成为一个scc),并对权值线段树进行合并。

查询就是所在scc的权值线段树的前k大之和,这个好办。

注意爆int。我写了300行7k......

 #include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <map> typedef long long LL;
const int N = , M = , V = ; struct Edge {
int nex, v;
}edge[M]; int tp; struct Node {
int t, x, y, id;
}node[M], t1[M], t2[M]; struct Ask {
int f, x, y;
LL ans;
}ask[M]; std::vector<Node> v[M];
std::stack<int> S;
std::map<int, int> mp[N];
int e[N], fr[N], stk[N], top, dfn[N], low[N], use[N], X[N + M], xx, rt[N], sum[V], ls[V], rs[V], val[N];
int Time, scc_cnt, num, n, m, q, tot;
LL Val[V]; inline void add(int x, int y) {
tp++;
edge[tp].v = y;
edge[tp].nex = e[x];
e[x] = tp;
return;
} namespace ufs {
int fa[N];
int find(int x) {
if(fa[x] == x) {
return x;
}
return fa[x] = find(fa[x]);
}
inline void merge(int x, int y) {
fa[find(x)] = find(y);
return;
}
inline void clear() {
for(int i = ; i <= n; i++) {
fa[i] = i;
}
return;
}
} void tarjan(int x) {
low[x] = dfn[x] = ++num;
S.push(x);
//printf("tarjan %d \n", x);
for(int i = e[x]; i; i = edge[i].nex) {
int y = edge[i].v;
if(!dfn[y]) {
tarjan(y);
low[x] = std::min(low[x], low[y]);
}
else if(!fr[y]) { // find
low[x] = std::min(low[x], dfn[y]);
}
}
if(low[x] == dfn[x]) {
//printf("getscc \n");
++scc_cnt;
int y;
do {
y = S.top();
//printf("%d ", y);
S.pop();
fr[y] = scc_cnt;
//ufs::merge(x, y);
} while(y != x);
//puts("");
}
return;
} inline void TAR() {
scc_cnt = num = ;
for(int i = ; i <= top; i++) {
if(!dfn[stk[i]]) {
tarjan(stk[i]);
}
}
return;
} inline void link(int x, int y) {
x = ufs::find(x); y = ufs::find(y);
if(use[x] != Time) {
use[x] = Time;
dfn[x] = fr[x] = e[x] = ;
stk[++top] = x;
}
if(use[y] != Time) {
use[y] = Time;
dfn[y] = fr[y] = e[y] = ;
stk[++top] = y;
}
add(x, y); // self-circle is OK
return;
} inline void solve(int L, int R, int l, int r) {
if(R < L) {
return;
}
//printf("solve %d %d %d %d \n", L, R, l, r);
if(l == r) {
for(int i = L; i <= R; i++) {
v[r].push_back(node[i]);
}
return;
}
int mid = (l + r) >> ;
++Time; top = tp = ;
for(int i = L; i <= R; i++) {
if(node[i].t <= mid) {
link(node[i].x, node[i].y);
}
}
//int ufs_t = ufs::top;
TAR();
int top1 = , top2 = ;
for(int i = L; i <= R; i++) {
int x = ufs::find(node[i].x), y = ufs::find(node[i].y);
if(node[i].t <= mid && fr[x] == fr[y]) {
t1[++top1] = node[i];
}
else {
t2[++top2] = node[i];
}
}
memcpy(node + L, t1 + , top1 * sizeof(Node));
memcpy(node + L + top1, t2 + , top2 * sizeof(Node));
solve(L, L + top1 - , l, mid);
for(int i = L; i < L + top1; i++) {
int x = ufs::find(node[i].x);
int y = ufs::find(node[i].y);
ufs::merge(x, y);
}
solve(L + top1, R, mid + , r);
return;
} int merge(int x, int y) {
if(!x || !y || x == y) {
return x | y;
}
int o = ++tot;
sum[o] = sum[x] + sum[y];
Val[o] = Val[x] + Val[y];
ls[o] = merge(ls[x], ls[y]);
rs[o] = merge(rs[x], rs[y]);
return o;
} void add(int p, int v, int l, int r, int &o) {
//printf("add : %d %d %d %d \n", p, v, l, r);
if(!o) {
o = ++tot;
}
if(l == r) {
sum[o] += v;
Val[o] += v * X[r];
return;
}
int mid = (l + r) >> ;
if(p <= mid) {
add(p, v, l, mid, ls[o]);
}
else {
add(p, v, mid + , r, rs[o]);
}
sum[o] = sum[ls[o]] + sum[rs[o]];
Val[o] = Val[ls[o]] + Val[rs[o]];
return;
} LL query(int k, int l, int r, int o) {
//printf("query %d [%d %d] \n", k, l, r);
if(!o) {
return ;
}
if(l == r) {
return 1ll * std::min(k, sum[o]) * X[r];
}
int mid = (l + r) >> ;
if(sum[rs[o]] >= k) {
return query(k, mid + , r, rs[o]);
}
else {
return Val[rs[o]] + query(k - sum[rs[o]], l, mid, ls[o]);
}
} int main() { scanf("%d%d%d", &n, &m, &q);
ufs::clear();
for(int i = ; i <= n; i++) {
scanf("%d", &val[i]);
X[++xx] = val[i];
}
for(int i = ; i <= m; i++) {
scanf("%d%d", &node[i].x, &node[i].y);
mp[node[i].x][node[i].y] = i;
node[i].id = i;
}
for(int i = ; i <= q; i++) {
scanf("%d%d%d", &ask[i].f, &ask[i].x, &ask[i].y);
if(ask[i].f == ) {
ask[i].y += val[ask[i].x];
X[++xx] = ask[i].y;
std::swap(val[ask[i].x], ask[i].y);
}
}
std::sort(X + , X + xx + );
xx = std::unique(X + , X + xx + ) - X - ;
for(int i = ; i <= n; i++) {
val[i] = std::lower_bound(X + , X + xx + , val[i]) - X;
}
for(int i = ; i <= q; i++) {
if(ask[i].f == ) {
ask[i].y = std::lower_bound(X + , X + xx + , ask[i].y) - X;
}
}
std::reverse(ask + , ask + q + );
for(int i = ; i <= q; i++) {
if(ask[i].f == ) {
int t = mp[ask[i].x][ask[i].y];
node[t].t = i;
}
} solve(, m, , q + );
//printf("--------------------------------\n");
ufs::clear();
for(int i = ; i <= n; i++) {
add(val[i], , , xx, rt[i]);
}
for(int i = ; i <= q; i++) {
//printf("i = %d \n", i);
for(int j = ; j < v[i].size(); j++) {
//printf(" > edge = %d %d \n", v[i][j].x, v[i][j].y);
int x = ufs::find(v[i][j].x), y = ufs::find(v[i][j].y);
ufs::merge(x, y);
int t = ufs::find(x);
rt[t] = merge(rt[x], rt[y]);
//printf("%d = merge %d %d \n", t, x, y);
}
if(ask[i].f == ) {
int t = ufs::find(ask[i].x);
ask[i].ans = query(ask[i].y, , xx, rt[t]);
}
else if(ask[i].f == ) {
int t = ufs::find(ask[i].x);
//printf("change %d : %d -> %d \n", ask[i].x, X[val[ask[i].x]], X[ask[i].y]);
add(val[ask[i].x], -, , xx, rt[t]);
add(ask[i].y, , , xx, rt[t]);
val[ask[i].x] = ask[i].y;
}
}
for(int i = q; i >= ; i--) {
if(ask[i].f == ) {
printf("%lld\n", ask[i].ans);
}
}
return ;
}

AC代码

对拍真是个好东西。

洛谷P5163 WD与地图的更多相关文章

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

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

  2. 洛谷 P5162 WD与积木 解题报告

    P5162 WD与积木 题目背景 WD整日沉浸在积木中,无法自拔-- 题目描述 WD想买\(n\)块积木,商场中每块积木的高度都是\(1\),俯视图为正方形(边长不一定相同).由于一些特殊原因,商家会 ...

  3. 洛谷P5159 WD与矩阵

    题目背景 WD整日沉浸在矩阵中,无法自拔-- 题目描述 WD特别喜欢矩阵,尤其是\(01\)矩阵. 一天,CX给了WD一个巨大的\(n\)行\(m\)列的\(01\)矩阵,WD发现这个矩阵每行.每列的 ...

  4. 洛谷P5162 WD与积木 [DP,NTT]

    传送门 思路 真是非常套路的一道题-- 考虑\(DP\):设\(f_n\)为\(n\)个积木能搭出的方案数,\(g_n\)为所有方案的高度之和. 容易得到转移方程: \[ \begin{align*} ...

  5. 洛谷 P5162 WD与积木【多项式求逆】

    设f[i]为i个积木能堆出来的种类,g[i]为i个积木能堆出来的种类和 \[ f[n]=\sum_{i=1}^{n}C_{n}^{i}g[n-i] \] \[ g[n]=\sum_{i=1}^{n}C ...

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

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

  7. 洛谷P5160 WD与循环

    我们看这段代码 int cnt = 0; for (int a_1 = 0; a_1 <= m; a_1++) { for (int a_2 = 0; a_1 + a_2 <= m; a_ ...

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

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

  9. 关于三目运算符与if语句的效率与洛谷P2704题解

    题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图.在每一格平原地形上最 ...

随机推荐

  1. C#大型电商项目优化(三)——扩展性与支付

    上一篇文章引来不少非议,笔者并非对EF有看法,而是针对不同的业务场景和框架背景,挑选不同的方案.每个方案都有其优势劣势,挑选最快速,最简单的方案,是笔者的初衷. 看评论也是学习的过程,然而有些只做评价 ...

  2. 回顾:前端模块化和AMD、CMD规范(全)

    先列举下一些著名言论: "我想定义一个 each 方法遍历对象,但页头的 util.js 里已经定义了一个,我的只能叫 eachObject 了,好无奈." "Requi ...

  3. 【2016.3.19】作业 分析一个很有(wu)趣(liao)的小程序

    问题1:这个程序要找的是符合什么条件的数? 能够整除2-32中所有数仅除了在此之中的两个相邻的数,比如能整除2-29,且不能整除30,31.当然,这只是举个例子. 问题2:这样的数存在么?符合这一条件 ...

  4. OSG 改变窗口大小

    viewer.realize();//需要realize,否则窗口为null osgViewer::GraphicsWindow *pWnd = dynamic_cast<osgViewer:: ...

  5. 13.14.15.16.17&《一个程序猿的生命周期》读后感

    13.TDS 的标准是什么,怎么样才能认为他是一个标准的TDS?? 14.软件的质量包括哪些方面,如何权衡软件的质量? 15.如何解决功能与时间的矛盾,优秀的软件团队会发布有已知缺陷的软件么? 16. ...

  6. linux命令学习head和tail

    linux命令head和tail是一对:more和less是一对. head和tail https://www.2cto.com/os/201507/414753.html 一个头,一个尾. tail ...

  7. 设备 VMnet0 上的网桥当前未运行。此虚拟机无法与主机或网络中的其他计算机通信。

    http://www.cnblogs.com/baihuitestsoftware/articles/4223552.html 因为试用Windows10教育版下的Docker打开过Hyper-V,虽 ...

  8. A glance for agile method

    看看Apache最新的JIRA,新版的JIRA是有Agile模块的. Scrum早有耳闻,接触得也比较多,Kanban一次面试中提到过.今日深入查阅KanBan: http://www.agilewe ...

  9. Docker for windows 入门一(下载安装)

    预安装条件,可以查阅官方文档,本人是Win10 x64(必要条件)教育版+开启Hyper-V(Feature特性),具体可参考云栖社区的文章: https://yq.aliyun.com/articl ...

  10. 自己站点的nginx 配置信息

    user www www; worker_processes auto; error_log /home/wwwlogs/nginx_error.log crit; pid /usr/local/ng ...