LOJ3146 APIO2019路灯(cdq分治+树状数组)
每个时刻都形成若干段满足段内任意两点可达。将其视为若干正方形。则查询相当于求历史上某点被正方形包含的时刻数量。并且注意到每个时刻只有O(1)个正方形出现或消失,那么求出每个矩形的出现时间和消失时间,就是裸的三维偏序,cdq分治+树状数组即可。
#include<bits/stdc++.h> using namespace std; #define ll long long #define inf 1000000010 #define N 300010 #define mp(x,y) make_pair((x),(y)) #define fi first #define se second #define time se.fi #define ans se.se #define val se.se #define left fi.fi #define right fi.se char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } typedef pair<int,int> pii; typedef pair<pii,pii> ppp; int n,m,t,u,v,a[N],tree[N]; char s[N]; set<ppp> seg; ppp b[N<<1],q[N]; pii o; struct data { ppp x;int op; bool operator <(const data&a) const { return x.time<a.x.time||x.time==a.x.time&&x.fi<a.x.fi||x.time==a.x.time&&x.fi==a.x.fi&&op<a.op; } }c[N*3],d[N*3]; void add(int k,int x){while (k<=n) tree[k]+=x,k+=k&-k;} int query(int k){int s=0;while (k) s+=tree[k],k-=k&-k;return s;} void solve(int l,int r) { if (l==r) return; int mid=l+r>>1; solve(l,mid); solve(mid+1,r); int cur=l-1; for (int i=mid+1;i<=r;i++) if (c[i].op==1) { while (cur<mid&&(c[cur+1].op==1||c[cur+1].x.left<=c[i].x.left)) { cur++; if (c[cur].op==0) add(c[cur].x.right,c[cur].x.val); } c[i].x.ans+=query(c[i].x.right); } for (;cur>=l;cur--) if (c[cur].op==0) add(c[cur].x.right,-c[cur].x.val); int i=l,j=mid+1; for (int k=l;k<=r;k++) if (i<=mid&&(j>r||c[i].x.left<c[j].x.left)) d[k]=c[i++];else d[k]=c[j++]; for (int k=l;k<=r;k++) c[k]=d[k]; } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(),m=read(); scanf("%s",s+1); for (int i=1;i<=n;i++) a[i]=s[i]-'0'; if (!a[1]) seg.insert(mp(o,o)); for (int i=1;i<=n;i++) if (a[i]) { int t=i; while (t<n&&a[t+1]==1) t++; seg.insert(mp(mp(i-1,t),o)); i=t; } else if (!a[i+1]) seg.insert(mp(mp(i,i),o)); for (int i=1;i<=m;i++) { /*for (auto it=seg.begin();it!=seg.end();it++) cout<<(*it).left<<' '<<(*it).right<<' '<<(*it).time<<endl; cout<<endl;*/ char c=getc(); if (c=='q') { int l=read()-1,r=read()-1; q[++t]=mp(mp(l,r),mp(i-1,0)); auto it=seg.upper_bound(mp(mp(l,n+1),o)); if (it!=seg.begin()) { it--; if ((*it).right>=r) q[t].ans=i-(*it).time; } } else { int x=read(); if (a[x]) { auto it=seg.lower_bound(mp(mp(x,0),o));it--; ppp tmp=*it;seg.erase(it); b[++u]=mp(tmp.fi,mp(i-1,i-tmp.time)); seg.insert(mp(mp(tmp.left,x-1),mp(i,0))); seg.insert(mp(mp(x,tmp.right),mp(i,0))); } else { auto it=seg.lower_bound(mp(mp(x,0),o)); auto it2=it;it2--; ppp tmp=*it;seg.erase(it); ppp tmp2=*it2;seg.erase(it2); b[++u]=mp(tmp.fi,mp(i-1,i-tmp.time)); b[++u]=mp(tmp2.fi,mp(i-1,i-tmp2.time)); seg.insert(mp(mp(tmp2.left,tmp.right),mp(i,0))); } a[x]^=1; } } n++; for (int i=1;i<=t;i++) q[i].right=n-q[i].right; for (int i=1;i<=u;i++) b[i].right=n-b[i].right; /*for (int i=1;i<=t;i++) cout<<q[i].left<<' '<<q[i].right<<' '<<q[i].time<<' '<<q[i].ans<<endl; cout<<endl; for (int i=1;i<=u;i++) cout<<b[i].left<<' '<<b[i].right<<' '<<b[i].time<<' '<<b[i].val<<endl;*/ //求left<=q[i].left right<=q[i].right time<=q[i].time 的权值和 /*for (int i=1;i<=t;i++) for (int j=1;j<=u;j++) if (b[j].left<=q[i].left&&b[j].right<=q[i].right&&b[j].time<=q[i].time) q[i].ans+=b[j].val;*/ for (int i=1;i<=t;i++) c[++v].x=q[i],c[v].op=1; for (int i=1;i<=u;i++) c[++v].x=b[i],c[v].op=0; sort(c+1,c+v+1); solve(1,v); sort(c+1,c+v+1); for (int i=1;i<=v;i++) if (c[i].op==1) printf("%d\n",c[i].x.ans); return 0; //NOTICE LONG LONG!!!!! }