糖糖别胡说,我真的不是签到题目
题目链接:https://ac.nowcoder.com/acm/problem/14583
题意很简单
做法:看到别人的做法都是差分求出最后的数值,然后倒着求答案。
今天我就来一个特殊的做法,直接正着模拟。开两棵线段树,维护0和1
① 遇到一个0 需要把种类为1的小于当前bi全部消掉,这里用权值线段树维护区间和+懒人标记 去更新
② 接着将当前这个0插入到0种类的线段树内。最后的答案就是sum[0][1]+sum[1][1]
③ 至于如何维护 施法 前面的数字全部加1呢?用一个基数base代表施法次数。每次遇到新的ai bi 将bi-base就能做到和前面的bi是一个维度的 接着base++
时间复杂度是n*log(mx(a[i]+m)
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=(b);++i) #define per(i,a,b) for(int i=a;i>=(b);--i) #define mem(a,x) memset(a,x,sizeof(a)) #define pb push_back #define pi pair<int, int> #define mk make_pair using namespace std; typedef long long ll; ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;} const int N=5e4+10,M=2e6+10; struct node { int ty,w; }a[N]; int n,m,len; int w[N],vis[N],l1; int sum[2][4*M],lazy[2][4*M]; void pushdown(int id,int ty) { if(lazy[ty][id]!=0){ lazy[ty][id<<1]=lazy[ty][id]; lazy[ty][id<<1|1]=lazy[ty][id]; sum[ty][id<<1]=0; sum[ty][id<<1|1]=0; lazy[ty][id]=0; } } void up(int id,int l,int r,int ql,int qr,int val,int ty) { if(ql<=l&&r<=qr){ if(val==-1) lazy[ty][id]=-1,sum[ty][id]=0; else lazy[ty][id]=0,sum[ty][id]+=1; return ; } pushdown(id,ty); int mid=l+r>>1; if(ql<=mid) up(id<<1,l,mid,ql,qr,val,ty); if(qr>mid) up(id<<1|1,mid+1,r,ql,qr,val,ty); sum[ty][id]=sum[ty][id<<1]+sum[ty][id<<1|1]; } void solve() { scanf("%d%d",&n,&m); mem(sum,0);mem(lazy,0);mem(vis,0); rep(i,1,n) { scanf("%d%d",&a[i].ty,&a[i].w); a[i].w+=m; } l1=0; rep(i,1,m) { int x;scanf("%d",&x); if(vis[x]==0) w[++l1]=x; vis[x]++; } sort(w+1,w+1+l1); int base=0;len=1; for(int i=1;i<=n;++i){ int ww=a[i].w-base; if(ww>1) up(1,1,M-10,1,ww-1,-1,1-a[i].ty); up(1,1,M-10,ww,ww,1,a[i].ty); while(len<=m&&i==w[len]) base+=vis[w[len]],len++; } int ans=sum[0][1]+sum[1][1]; printf("%d\n",ans); } int main() { //freopen("2.in", "r", stdin); int _;cin>>_;while(_--) solve(); }