1. 程式人生 > >Codeforces - 331B2 權值線段樹 區間合並

Codeforces - 331B2 權值線段樹 區間合並

bits turn 權值線段樹 lse 基本 基於 spa adr tail

題意:題目太玄了我無法用語言精簡..

題目要求的操作1是基於值的,所以用普通線段樹基本無法維護(反正我不知道)
換做權值型後十分好做,因為連接處必然是更後面的,這時比較一下位置就好
PS.感覺周賽越來越硬核了

#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i=j;i<=k;i++)
#define print(a) printf("%lld",(ll)(a))
#define println(a) printf("%lld\n",(ll)(a))
using namespace std;
const int
MAXN = 3e5+11; const int INF = 0x3f3f3f3f; typedef long long ll; int a[MAXN],pos[MAXN]; ll read(){ ll x=0,f=1;register char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } struct ST{ #define lc o<<1
#define rc o<<1|1 int cnt[MAXN<<2]; void pu(int o,int l,int r){ cnt[o]=cnt[lc]+cnt[rc]; int taillc=l+r>>1; int headrc=taillc+1; if(pos[taillc]<pos[headrc]) cnt[o]--; } void build(int o,int l,int r){ if(l==r){ cnt[o]=1
; return; } int mid=l+r>>1; build(lc,l,mid); build(rc,mid+1,r); pu(o,l,r); } ll query(int o,int l,int r,int L,int R){ if(L<=l&&r<=R){ return cnt[o]; } int mid=l+r>>1; ll ans1=0,ans2=0,ans3=0; if(L<=mid) ans1=query(lc,l,mid,L,R); if(R>mid) ans2=query(rc,mid+1,r,L,R); if(ans1&&ans2){ int taillc=l+r>>1; int headrc=taillc+1; if(pos[taillc]<pos[headrc]) ans3=-1; } return ans1+ans2+ans3; } void update(int o,int l,int r,int k,int v=1){ if(l==r){ return; } int mid=l+r>>1; if(k<=mid) update(lc,l,mid,k,v); else update(rc,mid+1,r,k,v); pu(o,l,r); } }st; int main(){ int n,m; while(cin>>n){ rep(i,1,n){ a[i]=read(); pos[a[i]]=i; } st.build(1,1,n); m=read(); rep(i,1,m){ int x,y,z; x=read();y=read();z=read(); if(x==1){ println(st.query(1,1,n,y,z)); }else{ int yy=a[y],zz=a[z]; swap(pos[yy],pos[zz]); swap(a[y],a[z]); st.update(1,1,n,yy,1); st.update(1,1,n,zz,1); } } } return 0; }

Codeforces - 331B2 權值線段樹 區間合並