您的位置:首页 > 其它

【SCOI2011】【线段树】棘手的操作

2013-03-30 11:55 155 查看
比较好的一道数据结构题。

初看题目很容易想到用并查集来维护森林中各个节点之间的关系,但是在合并的时候就会出现很多问题了。如果用并查集的话需要暴力地修改标记,维护最大值,然后需要堆来维护各个连通块的最优值,这样显得非常繁琐。

于是我们可以考虑设计离线算法,先将所有询问读入,把连通块之间的关系用并查集维护,并且保证大的节点接在小的节点后面,维护完之后我们就可以将每个连通块映射成为一个区间,这样题目中不管是询问还是更新都是在区间上操作。而在区间上操作的数据结构我们马上就可以想到使用线段树,这样我们可以以O(m)的预处理和O(mlogn)的时间来解决本题。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#define lson l,m,st << 1
#define rson m + 1,r,st << 1 | 1
using namespace std;
const int maxn = 300000 + 10;
const int inf = 0x3f3f3f3f;
struct Ques
{
char op[4];
int x,v;
}q[maxn];
int fa[maxn],end[maxn],pos[maxn],link[maxn],weight[maxn];
int Max[maxn<<2],add[maxn<<2];
int n,m;

void init()
{
freopen("bzoj2333.in","r",stdin);
freopen("bzoj2333.out","w",stdout);
}

void readdata()
{
scanf("%d",&n);
for(int i = 1;i <= n;i++)scanf("%d",&weight[i]);
scanf("%d",&m);
for(int i = 1;i <= m;i++)
{
scanf("%s",q[i].op);
if(q[i].op[0] == 'F')
{
if(q[i].op[1] == '3')continue;
else scanf("%d",&q[i].x);
}
else
{
if(q[i].op[1] == '3')scanf("%d",&q[i].x);
else scanf("%d%d",&q[i].x,&q[i].v);
}
}

}

int find(int x)
{
if(fa[x] == x)return x;
fa[x] = find(fa[x]);
return fa[x];
}

void make_sequence()
{
for(int i = 1;i <= n;i++)end[i] = fa[i] = link[i] = i;
for(int i = 1;i <= m;i++)
{
if(q[i].op[0] == 'U')
{
int x = find(q[i].x);
int y = find(q[i].v);
if(x > y)swap(x,y);
fa[y] = x;
link[end[x]] = y;
end[x] = end[y];
}
}
memset(end,0,sizeof(end));
int cnt = 0;
for(int i = 1;i <= n;i++)
{
int x = i;
while(!end[x])
{
end[x] = ++cnt;
pos[x] = end[x];
fa[x] = x;
x = link[x];
}
}
memcpy(link,weight,sizeof(weight));
for(int i = 1;i <= n;i++)
{
weight[pos[i]] = link[i];
}
}

void pushup(int st)
{
Max[st] = max(Max[st<<1] + add[st<<1],Max[st<<1|1] + add[st<<1|1]);
}

void build(int l,int r,int st)
{
add[st] = 0;
if(l == r)
{
Max[st] = weight[l];
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
pushup(st);
}

void update(int L,int R,int c,int l,int r,int st)
{
if(L <= l && r <= R)
{
add[st] += c;
return;
}
int m = (l + r) >> 1;
if(L <= m)update(L,R,c,lson);
if(R > m)update(L,R,c,rson);
pushup(st);
}

int query(int L,int R,int l,int r,int st)
{
if(L <= l && r <= R)return Max[st] + add[st];
int ret = -inf;
int m = (l + r) >> 1;
if(L <= m)ret = max(ret,query(L,R,lson));
if(R > m)ret = max(ret,query(L,R,rson));
return ret + add[st];
}

void solve()
{
make_sequence();
build(1,n,1);
for(int i = 1;i <= m;i++)
{
if(!strcmp(q[i].op,"U"))
{
int x = find(q[i].x);
int y = find(q[i].v);
if(x > y)swap(x,y);
fa[y] = fa[x];
end[x] = end[y];
}
if(!strcmp(q[i].op,"A1"))update(pos[q[i].x],pos[q[i].x],q[i].v,1,n,1);
if(!strcmp(q[i].op,"A2"))
{
int x = find(q[i].x);
update(pos[x],end[x],q[i].v,1,n,1);
}
if(!strcmp(q[i].op,"A3"))update(1,n,q[i].x,1,n,1);
if(!strcmp(q[i].op,"F1"))printf("%d\n",query(pos[q[i].x],pos[q[i].x],1,n,1));
if(!strcmp(q[i].op,"F2"))
{
int x = find(q[i].x);
printf("%d\n",query(pos[x],end[x],1,n,1));
}
if(!strcmp(q[i].op,"F3"))printf("%d\n",query(1,n,1,n,1));
}
}

int main()
{
init();
readdata();
solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: