【HDU 5997】 rausen loves cakes 【启发式合并+线段树】

题意:给你一段数字,要你完成两个操作

1.把所有数字x换成数字y

2.输出[l,r]中有几段不同的数字

题解:

这题可以采用启发式合并,也就是每次把个数少的往个数大的上面合并,这样如果要合并成n个一样的最坏的情况是nlogn的(n/2*logn)

然后合并的时候用线段树单点更新下就行

时间复杂度O(nlog2n)

注意:

可能会让你合并颜色没有的节点,所以在改变合并方向的标记的时候两边都要标记一下

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define PB push_back
#define MP make_pair
#define ll long long
#define MS(a,b) memset(a,b,sizeof(a))
#define LL (rt<<1)
#define RR (rt<<1|1)
#define lson l,mid,LL
#define rson mid+1,r,RR
#define pii pair
#define pll pair
#define lb(x) (x&(-x))
void In(){freopen("in.in","r",stdin);}
void Out(){freopen("out.out","w",stdout);}
const int N=1e5+10;
const int M=1e6+10;
const int Mbit=1e6+10;
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
vectorv[M];
int mp[M];
struct node
{
    int l,r,sum;
}tree[N<<2],ans;
void up(int rt)
{
    tree[rt].l=tree[LL].l;tree[rt].r=tree[RR].r;
    tree[rt].sum=tree[LL].sum+tree[RR].sum;
    if(tree[LL].r==tree[RR].l)tree[rt].sum--;
}
void build(int l,int r,int rt)
{
    if(l==r){
        int x;scanf("%d",&x);
        v[x].PB(l);
        tree[rt].l=tree[rt].r=x;
        tree[rt].sum=1;
        return;
    }
    int mid=l+r>>1;
    build(lson);
    build(rson);
    up(rt);
}
void update(int l,int r,int rt,int p,int col)
{
    if(l==r){
        tree[rt].l=tree[rt].r=col;
        return;
    }
    int mid=l+r>>1;
    if(p<=mid)update(lson,p,col);
    else      update(rson,p,col);
    up(rt);
}
node query(int l,int r,int rt,int L,int R)
{
    if(L<=l&&r<=R)return tree[rt];
    node t1,t2;
    int mid=l+r>>1;
    if(L<=mid)t1=query(lson,L,R);
    if(R>mid)t2=query(rson,L,R);
    if(L<=mid&&R>mid){
        t1.sum+=t2.sum;
        if(t1.r==t2.l)t1.sum--;
        t1.r=t2.r;
        return t1;
    }
    else if(R<=mid)return t1;
    else return t2;
}
int main()
{//In();
    int T,kase=0,q,n,op,x,y,a,b;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&q);
        for(int i=1;i


你可能感兴趣的:(ACM)