2019.7.10 義烏模擬賽 T4 D
阿新 • • 發佈:2021-07-10
考試的時候寫了個常數大的要命的程式碼。然後思維複雜度不知道比std高多少。
首先我們知道一個結論:聯通塊個數等於點數-邊數。
點數是平凡的,我們考慮邊數。
邊實質上是一個三維數點,三隻log顯然不行。
考慮對邊差分,所以有\([1,r]\)減去\([1,l-1]\),這樣是二維數點兩個log有70分。
發現點的編號和邊的編號是一樣的,這肯定有什麼特殊性質。
以\([1,r]\)為例,我們考慮什麼時候第\(i\)條邊\((x_i,y_i)\)有用。
顯然至少要在\(\max(i,x_i,y_i)\)條邊加入,且區間左端點大於等於\(\min(x_i,y_i)\)才能行。這個顯然二維偏序掃描線+樹狀陣列一個log。
\([1,l-1]\)
code:
#include<bits/stdc++.h> #define I inline #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define abs(x) ((x)>0?(x):-(x)) #define re register #define ll long long #define db double #define N 1000000 #define M 30 #define mod 1000000007 #define eps (1e-7) #define U unsigned int #define IT set<ques>::iterator #define Gc() getchar() #define Me(x,y) memset(x,y,sizeof(x)) using namespace std; int n,m,A[N+5],B[N+5],Minn[N+5],Maxn[N+5],x[N+5],y[N+5],Ans[N+5],F[N+5],now,cnt;vector<int> Gs[N+5],G[N+5]; I void read(int &x){ char s=getchar();x=0;while(s<'0'||s>'9') s=Gc(); while(s>='0'&&s<='9') x=x*10+s-48,s=Gc(); } I void print(int x){x>9&&(print(x/10),0);putchar(x%10+48);} I void get(int x,int y){while(x<=n) F[x]+=y,x+=x&-x;} I int find(int x){int ans=0;while(x) ans+=F[x],x-=x&-x;return ans;} int main(){ freopen("d.in","r",stdin);freopen("d.out","w",stdout); re int i,j;scanf("%d%d",&n,&m);for(i=1;i<n;i++) read(A[i]),read(B[i]),Maxn[i]=max(A[i],B[i]),Minn[i]=min(A[i],B[i]);for(i=1;i<=m;i++)read(x[i]),read(y[i]),Ans[i]=y[i]-x[i]+1; for(i=1;i<=m;i++) G[x[i]-1].push_back(i);for(i=1;i<n;i++){ Minn[i]>=i+1&&(get(Maxn[i],1),Gs[Minn[i]].push_back(i),0);for(j=0;j<Gs[i].size();j++) get(Maxn[Gs[i][j]],-1); for(j=0;j<G[i].size();j++)now=G[i][j],Ans[now]+=find(y[now]); }for(i=1;i<=n;i++) Gs[i].clear(),G[i].clear();Me(F,0); for(i=1;i<=m;i++) G[y[i]].push_back(i);for(i=1;i<n;i++) Gs[max(Maxn[i],i)].push_back(i); for(i=1;i<=n;i++){ for(j=0;j<Gs[i].size();j++) get(Minn[Gs[i][j]],1),cnt++;for(j=0;j<G[i].size();j++) now=G[i][j],Ans[now]-=cnt-find(x[now]-1); }for(i=1;i<=m;i++) print(Ans[i]),printf("\n"); }