题意:一个长为n的数组,q次操作,l,r,x,y,将区间[l,r]中等于x的数变为y,a[i],x,y<=100,n,q<=200000

题解:学到了。。。虽然以前好像做过类似的题,但这里没想到。注意到数值范围为[1,100],我们可以用线段树,每个节点开一个大小为100的数组f[i],表示这个区间内i应该变为f[i],然后应该就做完了。。。

#include<cstdio>
const int N=200010;
struct node{int l,r,f[101];}a[N<<2];
int n,m,b[N];
int read(){int d=0,f=1; char c=getchar(); while (c<'0'||c>'9'){if (c=='-') f=-1; c=getchar();} while (c>='0'&&c<='9') d=d*10+c-48,c=getchar(); return d*f;}
void build(int k,int l,int r)
{
    a[k].l=l; a[k].r=r;
    for (int i=1;i<=100;i++) a[k].f[i]=i;
    if (l==r) return;
    int mid=(l+r)>>1;
    build(k<<1,l,mid); build(k<<1|1,mid+1,r);
}
void pushdown(int k)
{
    int k1=k<<1,k2=k1|1;
    for (int i=1;i<=100;i++)
        a[k1].f[i]=a[k].f[a[k1].f[i]],
        a[k2].f[i]=a[k].f[a[k2].f[i]];
    for (int i=1;i<=100;i++) a[k].f[i]=i;
}
void update(int k,int l,int r,int x,int y)
{
    if (l<=a[k].l&&a[k].r<=r)
    {
        for (int i=1;i<=100;i++)
            if (a[k].f[i]==x) a[k].f[i]=y;
        return;
    }
    pushdown(k);
    int mid=(a[k].l+a[k].r)>>1;
    if (r<=mid) update(k<<1,l,r,x,y);
    else if (l>mid) update(k<<1|1,l,r,x,y);
    else update(k<<1,l,mid,x,y),update(k<<1|1,mid+1,r,x,y);
}
int ask(int k,int x)
{
    if (a[k].l==a[k].r) return a[k].f[b[x]];
    int mid=(a[k].l+a[k].r)>>1;
    if (x<=mid) return a[k].f[ask(k<<1,x)];
    else return a[k].f[ask(k<<1|1,x)];
}
int main()
{
    n=read();
    for (int i=1;i<=n;i++) b[i]=read();
    build(1,1,n);
    m=read();
    while (m--)
    {
        int l=read(),r=read(),x=read(),y=read();
        update(1,l,r,x,y);
    }
    for (int i=1;i<=n;i++) printf("%d ",ask(1,i));
    return 0;
}
View Code