1483: [HNOI2009]梦幻布丁

来源:互联网 发布:豪迪软件 编辑:程序博客网 时间:2024/05/17 07:30

题目链接

题目大意:维护数列,兹瓷两种操作:1.把所有x变成y
2.询问数列中的连续段数,相邻且相同的为一段

题解:先求一下初始的答案,记作ans,然后维护它

由于没有数据范围,考虑用平衡树启发式合并暴力

用若干个链表维护,一个链表维护一种颜色出现的各个位置

操作1:启发式合并链表,同时维护答案

便sizep[i]i,p[i]=ip[x],p[y]

操作2:输出ans……

这里的多个链表使用前向星实现……

我终于会链表了

我的收获:求初始答案然后维护似乎挺常见的

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define M 1000100int n,q,z,ans,t;int c[M],sz[M],head[M],p[M];struct edge{int to,nex;}e[M<<1];void add(int u,int v){e[t]=(edge){v,head[u]};head[u]=t++;}void merge(int x,int y){    if(x==y) return ;//!!!     if(sz[p[x]]>sz[p[y]]) swap(p[x],p[y]);    x=p[x];y=p[y];    if(!sz[x]) return ;//!!!    for(int i=head[x];i!=-1;i=e[i].nex){        if(c[e[i].to-1]==y) ans--;//维护相邻位置对答案的影响         if(c[e[i].to+1]==y) ans--;     }    for(int i=head[x];i!=-1;i=e[i].nex) c[e[i].to]=y;//修改     for(z=head[x];e[z].nex!=-1;z=e[z].nex);//找到链表x     e[z].nex=head[y];head[y]=head[x];head[x]=-1;//因为链表不需要考虑单调性,直接把链表y连到链表x后面     sz[y]+=sz[x];sz[x]=0;}void work(){    int opt,x,y;    while(q--)    {        scanf("%d",&opt);        if(opt==1) scanf("%d%d",&x,&y),merge(x,y);        else printf("%d\n",ans);    }}void init(){    t=0,memset(head,-1,sizeof(head));    scanf("%d%d",&n,&q);    for(int i=1;i<=n;i++)    {        scanf("%d",&c[i]);        if(c[i]!=c[i-1]) ans++;        sz[c[i]]++;p[c[i]]=c[i];        add(c[i],i);//用链表记录每个c[i]的位置     }}int main(){    init();    work();    return 0;} 
原创粉丝点击