题目:
题目:
我怎么也不会想到,这道题的正解会如此的暴力。。。
一开始我的做法是开一个桶记录一下每种元素的出现次数,每次查找的时候,枚举一个元素x,查询大于等于x+c的个数。
这样是n*m的,但是其实不同的元素个数只有sqrt(n)个,因为:1+2+3+……x=n,x最多为sqrt(n)
所以用一个vector或者set记录一下目前有值的元素是哪些,每一次只for那些即可。
查询的时候用树状数组维护即可。
复杂度:O(m*sqrt(n)*logn)
#include<bits/stdc++.h> using namespace std; #define ll long long #define ri register int #define N 100005 int tong[N],cnt[N],sum[N],fa[N],n,m,t[N*4]; set<int> st; int read() { int x=0,fl=1; char ch=getchar(); while(ch<'0' || ch>'9') { if(ch=='-') fl=-1; ch=getchar(); } while(ch<='9' && ch>='0') x=x*10+ch-'0',ch=getchar(); return x*fl; } int find(int x) { if(x==fa[x]) return x; return fa[x]=find(fa[x]); } void modify(int x,int v) { while(x<=n) { t[x]+=v; x+=(x&-x); } } ll query(int x) { ll ans=0; while(x>0) { ans+=t[x]; x-=(x&-x); } return ans; } ll work(int c) { ll ans=0; if(c==0){ ll x=query(n); return x*(x-1)/2; } set<int>::iterator it=st.begin();//set保证插入的元素都是有序的 for(it;it!=st.end();++it){ int tp=*it;//这样就可以遍历每一个元素 if(tp+c>n) break; ll x=query(n)-query(tp+c-1); ans+=1ll*x*tong[tp]; } return ans; } int main() { freopen("cards.in","r",stdin); freopen("cards.out","w",stdout); n=read(); m=read(); for(ri i=1;i<=n;++i) fa[i]=i,cnt[i]=1; tong[1]=n; modify(1,n); st.insert(1); while(m--){ int op=read(); if(op==1){ int x=read(), y=read(); int f1=find(x),f2=find(y); if(f1==f2) continue; tong[cnt[f2]]--; tong[cnt[f1]]--; modify(cnt[f2],-1); modify(cnt[f1],-1); if(!tong[cnt[f2]]) st.erase(cnt[f2]); if(!tong[cnt[f1]]) st.erase(cnt[f1]); cnt[f2]+=cnt[f1]; if(!tong[cnt[f2]]) st.insert(cnt[f2]); modify(cnt[f2],1); tong[cnt[f2]]++; fa[f1]=f2; cnt[f1]=-1; } else{ int c=read(); printf("%lld\n",work(c)); } } return 0; } /* 7 5 2 1 1 4 1 2 3 2 1 2 0 */