题目链接
题目大意
这个题目也太难了把。。
不看代码写,我感觉基本写不出
还有要注意mid需要有时候移位
官方题解有点小问题 分母应该是(n(n-1))
还有一段大佬的话,看起来更好理解
当前一共有 all 个卡牌,分母显然是 all * (all - 1) (就我们只需要考虑排列的前两个数,后面的不影响)然后,对于卡牌 i ,设 <i 的卡牌有 a 张, >i 的卡牌有 b 张,那么卡牌 i 一定挑 a,b 中大的那个方向选,所以可以发现存在一个分界线 x ,使得 <=x 的卡牌按大于它的策略,>x的卡牌按小于它的策略计算分子的话,就考虑卡牌对 (i,j) 对答案的贡献,如果它属于横跨分界线的,则先 i 后 j 和先 j 后 i 都是可行的;如果 (i,j) 在同一块里(即要么 i,j 都 <= x 要么 i,j 都 >x),那么它们先 i 后 j 和 先 j 后 i 中恰好有一个能产生贡献。所以我代码里那个就是 all * (all - 1) / 2 ,这个计算的就是假设 (i,j) 只有一个产生贡献,然后 all * (all - num) 就是跨越块新增的贡献,再减去 ban (指的就是 (i,i) 这种情形多算了,要被减掉)
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug printf(" I am here
");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pii;
mt19937 rnd(time(0));
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=2e5+5,inf=0x3f3f3f3f,mod=20071027;
const double eps=1e-10;
int n,q;
ll sz;
ll a[maxn];
ll tree1[maxn<<2],tree2[maxn<<2];
void push(int node){
tree1[node]=tree1[node<<1]+tree1[node<<1|1]+tree2[node<<1]*tree2[node<<1|1];
tree2[node]=tree2[node<<1]+tree2[node<<1|1];
}
void build(int node,int l,int r){
if(l==r){
tree1[node]=a[l]*a[l];
tree2[node]=a[l];
return ;
}
int mid=(l+r)/2;
build(node<<1,l,mid);
build(node<<1|1,mid+1,r);
push(node);
}
void update(int node,int l,int r,int pos,int add){
if(l==r){
tree2[node]+=add;
tree1[node]=tree2[node]*tree2[node];
return ;
}
int mid=(l+r)/2;
if(mid>=pos) update(node<<1,l,mid,pos,add);
else update(node<<1|1,mid+1,r,pos,add);
push(node);
}
pii query_ans(int node,int L,int R,int l,int r){
if(L>r||R<l){
return {0,0};
}
if(L<=l&&r<=R){
return {tree1[node],tree2[node]};
}
int mid=(l+r)/2;
pii sum={0,0},temp1={0,0},temp2={0,0};
if(mid>=L) temp1=query_ans(node<<1,L,R,l,mid);
if(mid<R) temp2=query_ans(node<<1|1,L,R,mid+1,r);
sum={temp1.fi+temp2.fi+temp1.se*temp2.se,temp1.se+temp2.se};
return sum;
}
int query_mid(int node,int l,int r,int sz){// 线段树上二分找分界点
if(l==r){
return l;
}
int mid=(l+r)/2,ans=-1;
if(tree2[node<<1]>=sz) ans=query_mid(node<<1,l,mid,sz);
else ans=query_mid(node<<1|1,mid+1,r,sz-tree2[node<<1]);
return ans;
}
signed main(){
int _;scanf("%d",&_);
while(_--){
for(int i=1;i<=200000;i++){
a[i]=0;
}
scanf("%d%d",&n,&q);
for(int i=1,x;i<=n;i++){
scanf("%d",&x);
a[x]++;
}
sz=n;
build(1,1,200000);
for(int i=1,opt,pos,add;i<=q;i++){
scanf("%d",&opt);
if(opt==1){
scanf("%d%d",&add,&pos);
sz+=add;
update(1,1,200000,pos,add);
}else{
int mid=query_mid(1,1,200000,sz/2);
ll sum=query_ans(1,1,mid,1,200000).se,val=query_ans(1,mid,mid,1,200000).se;
if(sum-val>=sz-sum) mid--;
pii a=query_ans(1,1,mid,1,200000);
pii b=query_ans(1,mid+1,200000,1,200000);
// 去重自己不能选择自己
a.fi-=a.se;
b.fi-=b.se;
ll mu=sz*(sz-1);
ll zi=mu-a.fi-b.fi;
ll g=__gcd(mu,zi);
printf("%lld/%lld
",zi/g,mu/g);
}
}
}
return 0;
}