NOIP 模擬 9 數顏色
阿新 • • 發佈:2021-06-22
題解
一道裸的資料結構題
正解是排序 \(+\) 二分,但是這怎麼能有動態開點線段樹好寫呢?
於是我就打了暴力,騙了五十分。
對於每種顏色,我們在下標上開一顆線段樹,對於交換若顏色相同則跳過,否則直接修改兩種顏色的線段樹。
跟正解一樣是 \(\mathcal O(nlogn)\),但常數巨大,慢三倍還多
Code:
#include<bits/stdc++.h> #define ri register signed #define p(i) ++i using namespace std; namespace IO{ char buf[1<<21],*p1=buf,*p2=buf; #define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++ inline int read() { ri x=0,f=1;char ch=gc(); while(ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=gc();} while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=gc();} return x*f; } } using IO::read; namespace nanfeng{ #define cmax(x,y) ((x)>(y)?(x):(y)) #define cmin(x,y) ((x)>(y)?(y):(x)) #define FI FILE *IN #define FO FILE *OUT static const int N=3e5+7; int a[N],n,m; struct Seg{ #define ls(x) T[x].l #define rs(x) T[x].r #define sum(x) T[x].sum struct Segmenttree{int l,r,sum;}T[N<<5]; int rt[N],tot; inline void up(int x) { int l=ls(x),r=rs(x); sum(x)=sum(l)+sum(r); } void update(int &x,int l,int r,int p,int w) { if (!x) x=p(tot); if (l==r) {sum(x)+=w;return;} int mid((l+r)>>1); if (p<=mid) update(ls(x),l,mid,p,w); else update(rs(x),mid+1,r,p,w); up(x); } int query(int x,int l,int r,int lt,int rt) { if (!x) return 0; if (l<=lt&&rt<=r) return sum(x); int mid((lt+rt)>>1),res=0; if (l<=mid) res+=query(ls(x),l,r,lt,mid); if (r>mid) res+=query(rs(x),l,r,mid+1,rt); return res; } }T; inline int main() { // FI=freopen("nanfeng.in","r",stdin); // FO=freopen("nanfeng.out","w",stdout); n=read(),m=read(); for (ri i(1);i<=n;p(i)) { int c=read();a[i]=c; T.update(T.rt[c],1,n,i,1); } for (ri i(1);i<=m;p(i)) { int t=read(); if (t==1) { int l=read(),r=read(),c=read(); printf("%d\n",T.query(T.rt[c],l,r,1,n)); } else { int x=read(); if (a[x]==a[x+1]) continue; T.update(T.rt[a[x]],1,n,x,-1); T.update(T.rt[a[x]],1,n,x+1,1); T.update(T.rt[a[x+1]],1,n,x+1,-1); T.update(T.rt[a[x+1]],1,n,x,1); swap(a[x],a[x+1]); } } return 0; } } int main() {return nanfeng::main();}