Problem A
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4100
题意:
以连通块中元素个数为权值,建立线段树,维护三个变量,分别是cnt(这样的连通块的数量),sum(连通块的总的点数),pfh(各连通块之间点数的平方和)(注意不是和的平方)
cnt代表连通块数量,tot_ret代表当前状态下的图,在不增长连通块个数的前提下,可以加的边数。
所以对于最小值很显然。
对于最大值,首先减去块内连的边,然后去线段树查询剩下的边怎么加,首先填连通块元素大小大的,这样也就是类似查询第k大,查到叶子结点,再判断
块中元素为tree[cur].l的 块 我需要多少个 返回回去,就行了。
PS:卡cin
题解:权值线段树 + 并查集 + 二分
C++版本一
#include<bits/stdc++.h>
using namespace std;
typedef long long ll ;
typedef pair<int,int>PII;
const int MAX = 2e5 + 10;
int n, q,cnt,f[MAX];
ll tot_ret,ret[MAX],num[MAX];
int get(int v)
{
return f[v] == v ? v : f[v] = get(f[v]);
}
struct node
{
int l,r ;
ll cnt, sum, pfh;
} tree[MAX << 2];
void pushup(int cur)
{
tree[cur].cnt = tree[cur << 1].cnt + tree[cur << 1|1].cnt;
tree[cur].sum = tree[cur << 1].sum + tree[cur << 1|1].sum;
tree[cur].pfh = tree[cur << 1].pfh + tree[cur << 1|1].pfh;
}
void build(int l, int r, int cur)
{
tree[cur].l = l;
tree[cur].r = r;
if(l == r)
{
tree[cur].pfh = tree[cur].sum = tree[cur].cnt = (l == 1? n : 0);
return ;
}
int mid = (l + r) >> 1;
build(l,mid,cur << 1) ;
build(mid+1,r,cur << 1|1) ;
pushup(cur);
}
void update(int cur, ll tar, ll val)
{
if(tree[cur].l == tree[cur].r)
{
tree[cur].cnt += val;
tree[cur].sum += val * tar;
tree[cur].pfh += val * tar * tar;
return ;
}
int mid = (tree[cur].l + tree[cur].r) >> 1;
if(tar <= mid) update(cur << 1, tar, val);
else update(cur << 1|1,tar,val);
pushup(cur);
}
ll query(int cur, ll k, int sum)
{
if(tree[cur].l == tree[cur].r)
{
ll l = 1,r = tree[cur].cnt,mid;
mid = (l + r) >> 1;
while(l < r)
{
mid = (l + r) >> 1;
if(mid * (mid - 1)/2*tree[cur].l* tree[cur].l + mid * tree[cur].l * sum >= k)r =mid;
else l = mid + 1;
}
return l;
}
int mid = (tree[cur].l + tree[cur].r) >> 1;
ll tmp = (tree[cur << 1 | 1].sum * tree[cur << 1 | 1].sum - tree[cur << 1 | 1].pfh)/2 + tree[cur << 1 | 1].sum * sum;
if(tmp < k)
return tree[cur << 1 | 1].cnt + query(cur << 1,k - tmp,sum + tree[cur<<1 | 1].sum);
else return query(cur << 1 |1,k,sum);
}
ll cal(ll k)
{
if(k <= tot_ret) return cnt ;
k -= tot_ret;
ll tmp = query(1,k,0);
return cnt - tmp + 1;
}
int main()
{
//ios::sync_with_stdio(false); cin.tie(0);cout.tie(0);
int t ;
cin >> t;
while(t--)
{
scanf("%d%d",&n,&q);
//cin >> n >> q;
for(int i = 1; i <= n ; i++)
f[i] = i, num[i] = 1,ret[i] = 0;
tot_ret = 0,cnt = n;
build(1,n,1);
while(q--)
{
int op;
scanf("%d",&op);
//cin >> op;
if(op == 1)
{
int a, b;
scanf("%d %d",&a,&b);
//cin >> a >> b;
a= get(a), b = get(b);
if(a == b)
{
ret[a] --;
tot_ret--;
continue ;
}
if(num[a] > num[b]) swap(a,b);
update(1,num[a],-1);
update(1,num[b],-1);
f[a] = b;
tot_ret += num[a] * num[b] - 1;
cnt--;
ret[b] = ret[a] + ret[b] + num[a] * num[b] - 1;
num[b] += num[a];
ret[a] = num[a] = 0;
update(1,num[b],1);
}
else
{
ll k ;
scanf("%lld",&k);
// cin >> k;
ll minn = max(1LL, cnt - k);
ll maxx = cal(k);
printf("%lld %lld\n",minn,maxx);
//cout << minn << " " << maxx << endl;
}
}
}
return 0;
}
C++版本二
原博客
#include<bits/stdc++.h>
using namespace std;
#define mid (l+r)/2
int i,i0,n,m,T,pre[100005],siz[100005];
long long sum,num;
int fin(int x){
return (pre[x]==x)?x:pre[x]=fin(pre[x]);}
void uni(int x,int y){
if(fin(x)!=fin(y))pre[fin(y)]=fin(x);}
struct node
{
long long siz,siz2,siz3;
}tree[400005];
node operator+(node a,node b){
return {
a.siz+b.siz,a.siz2+b.siz2,a.siz3+b.siz3};}
void b_tree(int l,int r,int p)
{
if(l==r&&l==1)tree[p].siz=tree[p].siz3=n,tree[p].siz2=0;
else tree[p].siz=tree[p].siz2=tree[p].siz3=0;
if(l!=r)b_tree(l,mid,p*2),b_tree(mid+1,r,p*2+1);
}
void add_tree(int l,int r,int p,int a)
{
if(l==r)tree[p].siz+=l,tree[p].siz2+=l*(l-1)/2,tree[p].siz3++;
else
{
if(a<=mid) add_tree(l,mid,p*2,a);
else if(a>=mid+1)add_tree(mid+1,r,p*2+1,a);
tree[p]=tree[p*2]+tree[p*2+1];
}
}
void erase_tree(int l,int r,int p,int a)
{
if(l==r)tree[p].siz-=l,tree[p].siz2-=l*(l-1)/2,tree[p].siz3--;
else
{
if(a<=mid) erase_tree(l,mid,p*2,a);
else if(a>=mid+1)erase_tree(mid+1,r,p*2+1,a);
tree[p]=tree[p*2]+tree[p*2+1];
}
}
int q_tree(int l,int r,int p,long long k,long long v)
{
if(l==r)
{
int ll=1,rr=tree[p].siz3;
while(ll<rr)
{
int mmid=(ll+rr)/2;
if((v+mmid*l)*(v+mmid*l-1)/2>=l*(l-1)/2*mmid+k)rr=mmid;
else ll=mmid+1;
}
return ll;
}
else
{
if((v+tree[p*2+1].siz)*(v+tree[p*2+1].siz-1)/2>=k+tree[p*2+1].siz2)return q_tree(mid+1,r,p*2+1,k,v);
else return q_tree(l,mid,p*2,k+tree[p*2+1].siz2,v+tree[p*2+1].siz)+tree[p*2+1].siz3;
}
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&m);
for(i=1;i<=n;i++)pre[i]=i,siz[i]=1;
sum=0,num=n;
b_tree(1,n,1);
for(i=1;i<=m;i++)
{
int op;
scanf("%d",&op);
if(op==1)
{
int x,y;
scanf("%d %d",&x