题意:给你一段数字,要你完成两个操作
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