题目描述
在古老的宝兰国有 N 座城市和 M 条双向道路。随着时间的流逝,一些道路渐渐变得破旧,最后因为损坏而无法使用,而从来没有人维修这些道路。作为古宝兰国历史的热爱者,你想要做一个小小的研究。为此,你想要写一个程序来处理以下的操作:
• D K,代表输入中的第 K 条道路损坏了。道路从 1 开始编号;
• P A B,代表编号为 A 的城市的人口数变为了 B。
我们称一些城市构成的集合为一个区域,当且仅当对于集合中的任意两座城市,都可以通过没有损坏的道路,仅经过集合中的城市互相到达。区域的人口数即为集合中所有城市的人口数之和。
给定初始的道路、人口数,以及 M 个操作。你的任务就是,在每次询问后输出人口数最大的区域中有多少个城市。
输入格式
输入数据的第一行包含三个整数 N、M 和 Q,分别代表城市数、道路数和操作数。接下来一行包含 N 个整数 P1, P2, . . . , PN,以空格隔开,代表每个城市的人口数。接下来 M 行,每行包含两个整数 Xj 和 Yj,代表编号为 Xj 和 Yj 之间有一条双向道路。接下来 Q 行,每行包含一个操作,格式如题目描述中所述。
输出格式
输出 Q 行,依次代表每次操作后人口数最多的区域的大小。
并查集。既然它是删边那我就反过来倒着加边。30分。(树状数组说好的logn复杂度?但求区间最值好像不止这点。。。
数列每次修改一个数值求最大值?看了大神代码果然用优先队列过的(然而并不理解为什么可以用while过滤。。。
然后注意一下以后在codechef上提交都用lld,不然会WA
#include<iostream>
#include<algorithm>
#include<string>
#include<map>//ll dx[4]={0,0,-1,1};ll dy[4]={-1,1,0,0};
#include<set>//
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define ll long long
#define lowbit(x) (x) & (-x)
using namespace std;
map<char,int> r[27];
struct node{
int a,b,c;
}x[500005];
struct node2{
char a;
int b,c,d;
}y[500005];
int fa[500005];
int n,m,q;
int find(int v){
if (fa[v] == v)
return v;
else
return fa[v]=find(fa[v]);
}
int g[500005];
int c2[500010],w[500005];
void update2(int ii,int val){ //修改点
w[ii]=val;
for(int i=ii; i<=n+5; i+=lowbit(i)){
if(val>c2[i])
c2[i]=val;
else
break;
}
}
int query(int l, int r){
int s=w[r];//上边界
while (l!=r){
for(r-=1;r-lowbit(r)>=l;r-=lowbit(r)){
s=max(s,c2[r]);//注意计算区间,不要夸区间
}
s=max(s,w[r]); //下边界
}
return s;
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=0;i<=n;++i){
fa[i]=i;
}
for(int i=1;i<=n;++i){
scanf("%d",&g[i]);
update2(i,g[i]);
}
for(int i=1;i<=m;++i){
scanf("%d%d",&x[i].a,&x[i].b);
x[i].c=0;
}
for(int i=0;i<q;++i){
getchar();
scanf("%c",&y[i].a);
if(y[i].a=='D'){
scanf("%d",&y[i].b);
x[y[i].b].c=1;
}
else{
scanf("%d%d",&y[i].b,&y[i].c);
int tmp=y[i].c;
y[i].c=g[y[i].b];
g[y[i].b]=tmp;
update2(y[i].b,tmp);
}
}
int maxx=0,ss=0;
for(int i=1;i<=m;++i){
if(x[i].c==1){
maxx=max(w[x[i].a],maxx);
maxx=max(w[x[i].b],maxx);
continue;
}
int aa=find(x[i].a),bb=find(x[i].b);
if(aa!=bb){
fa[aa]=bb;
update2(bb,w[bb]+w[aa]);
update2(aa,0);
if(w[bb]>maxx){
maxx=w[bb];
}
}
}
for(int i=q-1;i>=0;--i){
y[i].d=query(1,n);
if(y[i].a=='D'){
int p=y[i].b;
int aa=find(x[p].a),bb=find(x[p].b);
if(aa!=bb){
fa[aa]=bb;
update2(bb,w[bb]+w[aa]);
update2(aa,0);
}
}
else{
int p=y[i].b;
int aa=find(p);
update2(aa,w[aa]+y[i].c-g[p]);
g[p]=y[i].c;
}
}
for(int i=0;i<q;++i)
printf("%d\n",y[i].d);
}
【线段树版100分代码】
#include<iostream>
#include<algorithm>
#include<string>
#include<map>//ll dx[4]={0,0,-1,1};ll dy[4]={-1,1,0,0};
#include<set>//
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define ll long long
#define MAXM 500005
#define lowbit(x) (x) & (-x)
using namespace std;
struct node{
int a,b,c;
}x[500005];
struct node2{
char a;
int b;
ll c,d;
}y[500005];
int fa[500005];
int n,m,q;
int find(int v){
if (fa[v] == v)
return v;
else
return fa[v]=find(fa[v]);
}
ll g[500005];
ll w[500005];
struct SegTree //求最值
{
struct node
{
long long num, sum;
}tree[MAXM << 2];
int L, R;
long long V;
void pushDown(int u, int l, int r, int m)//向下更新节点(节省时间)
{
if (tree[u].num != 0)
{
node &lson = tree[u << 1], &rson = tree[u << 1 | 1];
lson.num += tree[u].num;
rson.num += tree[u].num;
tree[u].sum += tree[u].num;
tree[u].num = 0;
}
}
void pushUp(int u) //【改】
{
tree[u].sum = max(tree[u << 1].sum + tree[u << 1].num, tree[u << 1 | 1].sum + tree[u << 1 | 1].num);
}
void built(int u, int l, int r)
{
tree[u].num = 0;
if (l == r)
{
tree[u].sum = 0;
return;
}
int mid = l + r >> 1;
built(u << 1, l, mid);
built(u << 1 | 1, mid + 1, r);
pushUp(u);
}
void _add(int u, int l, int r)//区间或者点加值
{
int mid = l + r >> 1;
if (L <= l&&r <= R)
{
tree[u].num += V; //【改,求和是V*(r-l+1)】 //【改=会错】
pushDown(u, l, r, mid);
return;
}
pushDown(u, l, r, mid);
if (L <= mid)
_add(u << 1, l, mid);
if (R>mid)
_add(u << 1 | 1, mid + 1, r);
pushUp(u);
}
long long _query(int u, int l, int r)
{
int mid = l + r >> 1;
if (L <= l&&r <= R)
{
pushDown(u, l, r, mid);
return tree[u].sum;
}
pushDown(u, l, r, mid);
long long cnt = 0;
if (L <= mid)
cnt = max(cnt, _query(u << 1, l, mid)); //【改】
if (mid<R)
cnt = max(cnt, _query(u << 1 | 1, mid + 1, r)); //【改】
pushUp(u);
return cnt;
}
void add(int l, int r, long long v)
{
L = l;
R = r;
V = v;
_add(1, 1, n);
}
long long query(int l, int r)
{
if (l <= r)
{
L = l, R = r;
return _query(1, 1, n);
}
else
return 0;
}
}A;
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=0;i<=n;++i){
fa[i]=i;
}
for(int i=1;i<=n;++i){
scanf("%lld",&g[i]); //每个城市的人口数
w[i]=g[i];
A.add(i,i,g[i]);
}
for(int i=1;i<=m;++i){
scanf("%d%d",&x[i].a,&x[i].b); //编号之间有一条双向道路
}
for(int i=0;i<q;++i){
getchar();
scanf("%c",&y[i].a);
if(y[i].a=='D'){
scanf("%d",&y[i].b); //第 K 条道路损坏了
x[y[i].b].c=1;
}
else{
scanf("%d%lld",&y[i].b,&y[i].c); //编号为 A 的城市的人口数变为了 B
ll tmp=y[i].c;
A.add(y[i].b,y[i].b,tmp-g[y[i].b]);
y[i].c=g[y[i].b];
g[y[i].b]=tmp;
w[y[i].b]=tmp;
}
}
for(int i=1;i<=m;++i){
if(x[i].c==1)
continue;
int aa=find(x[i].a),bb=find(x[i].b);
if(aa!=bb){
fa[aa]=bb;
A.add(bb,bb,w[aa]);
A.add(aa,aa,-w[aa]);
w[bb]+=w[aa];
w[aa]=0;
}
}
for(int i=q-1;i>=0;--i){
y[i].d=A.query(1,n);
if(y[i].a=='D'){
int p=y[i].b;
int aa=find(x[p].a),bb=find(x[p].b);
if(aa!=bb){
fa[aa]=bb;
A.add(bb,bb,w[aa]);
A.add(aa,aa,-w[aa]);
w[bb]+=w[aa];
w[aa]=0;
}
}
else{
int p=y[i].b;
int aa=find(p);
A.add(aa,aa,y[i].c-g[p]);
w[aa]+=y[i].c-g[p];
g[p]=y[i].c;
}
}
for(int i=0;i<q;++i)
printf("%lld\n",y[i].d);
return 0;
}
用set的方法:
每次要合并就先把set里面的a和b先删掉(用pair存,默认以first优先排序),再ab合并后把新的根节点和值重新存进去。
更改点:先把set里面的这个点删掉(搜根节点),重新计算点值后存入
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 5e5 + 5;
int type,q,u,v,m;
ll val[N];
pair < int ,int > edges[N];
int uf[N];
ll prev[N];
int good[N];
int a[N];
int b[N];
ll ans[N];
string cur[N];
set < pair < ll , int > , greater < pair < ll , int > > > DSU;
ll QUERY(){
set < pair < ll , int > > :: iterator it = DSU.begin();
return it->first;
}
int FIND(int u)
{
if(uf[u]!=uf[uf[u]]){
uf[u] = FIND(uf[u]);
}
return uf[u];
}
void UNION(int u , int v)
{
int xx = FIND(u);
int yy = FIND(v);
if(xx==yy) return;
DSU.erase(make_pair(val[xx],xx));
DSU.erase(make_pair(val[yy],yy));
uf[yy] = xx;
val[xx] += val[yy];
DSU.insert(make_pair(val[xx],xx));
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t,n;
cin >> n >> m >> q;
for(int i = 1; i<=n; ++i){
cin >> val[i];
uf[i] = i;
}
for(int i = 1; i<=m; ++i){
cin >> u >> v;
edges[i] = make_pair(u,v);
good[i] = true;
}
for(int i = 1; i<=q; ++i){
cin >> cur[i];
if(cur[i][0]=='D'){
cin >> a[i];
good[a[i]] = false;
}
else{
cin >> a[i] >> b[i];
prev[i] = val[a[i]];
val[a[i]] = b[i];
}
}
for(int i = 1; i<=n; ++i){
DSU.insert(make_pair(1LL * val[i],i));
}
for(int i = 1; i<=m; ++i){
if(good[i]){
UNION(edges[i].first,edges[i].second);
}
}
ans[q] = QUERY();
for(int i = q; i > 0; --i){
if(cur[i][0]=='D'){
UNION(edges[a[i]].first,edges[a[i]].second);
}
else{
int ind = a[i];
int newval = b[i];
int leader = FIND(ind);
DSU.erase(make_pair(val[leader],leader));
val[leader] -= newval;
val[leader] += prev[i];
DSU.insert(make_pair(val[leader],leader));
}
ans[i-1] = QUERY();
}
for(int i = 1; i<=q; ++i){
cout << ans[i] << endl;
}
return 0;
}