2018.8.22 附加赛4(HEOI2018模拟赛)
时间:3h+(实际)
期望得分:100+10+0
实际得分:100+10+0
BC毒瘤啊 暴力也没什么好写的
A 立体几何题(线段树 动态开点/树状数组)
就是求(sum_{i=1}^nsum_{j=1}^nmin(A[i],B[j]))。同时有(m)次单个元素修改。
当然不能直接算。考虑每个数会被算多少次:$$Ans=sum_{i=1}^nA[i] imessum_{j=1}^n[A[i]leq B[j]]+sum_{i=1}^nB[i] imessum_{j=1}^n[B[i]<A[j]]$$
这用树状数组维护就可以了。
至于修改,因为每次只改一个元素,比如改(A[i]),只可能影响到它对(n)个(B[ ])的贡献和(n)个(B[ ])对它的贡献。这个区间查一下个数和(B[ ])的区间和就行了。然后单点修改(A[i])。
动态开点的值域线段树或是离散化后树状数组都行,后者常数更优。
不卡空间也不强制在线的话就没必要上平衡树了。
#include <cstdio>
#include <cctype>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=200005*28;//log(1e8)!
int n,A[100005],B[100005];
char IN[MAXIN],*SS=IN,*TT=IN;
struct Segment_Tree
{
#define lson son[x][0]
#define rson son[x][1]
int tot,son[N][2],sz[N];
LL sum[N];
#define Update(x) sum[x]=sum[lson]+sum[rson], sz[x]=sz[lson]+sz[rson]
void Insert(int &x,int l,int r,int pos)
{
if(!x) x=++tot;
if(l==r)
{
++sz[x], sum[x]+=pos;
return;
}
int m=l+r>>1;
if(pos<=m) Insert(lson,l,m,pos);
else Insert(rson,m+1,r,pos);
Update(x);
}
void Delete(int x,int l,int r,int pos)
{
if(!x) return;//x=++tot;
if(l==r)
{
--sz[x], sum[x]-=pos;
return;
}
int m=l+r>>1;
if(pos<=m) Delete(lson,l,m,pos);
else Delete(rson,m+1,r,pos);
Update(x);
}
LL Query_Sum(int x,int l,int r,int L,int R)
{
if(!sz[x]) return 0;
if(L<=l && r<=R) return sum[x];
int m=l+r>>1;
if(L<=m)
if(m<R) return Query_Sum(lson,l,m,L,R)+Query_Sum(rson,m+1,r,L,R);
else return Query_Sum(lson,l,m,L,R);
return Query_Sum(rson,m+1,r,L,R);
}
int Query_Num(int x,int l,int r,int L,int R)
{
if(!sz[x]) return 0;
if(L<=l && r<=R) return sz[x];
int m=l+r>>1;
if(L<=m)
if(m<R) return Query_Num(lson,l,m,L,R)+Query_Num(rson,m+1,r,L,R);
else return Query_Num(lson,l,m,L,R);
return Query_Num(rson,m+1,r,L,R);
}
}TA,TB;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
int main()
{
// freopen("ex_graph3.in","r",stdin);
// freopen("graph.out","w",stdout);
#define R 100000001
#define SA RTA,0,R//from 0!
#define SB RTB,0,R
n=read(); int RTA=0, RTB=0;
for(int i=1; i<=n; ++i) TA.Insert(SA,A[i]=read());
for(int i=1; i<=n; ++i) TB.Insert(SB,B[i]=read());
LL Ans=0;
for(int i=1; i<=n; ++i) Ans+=1ll*A[i]*TB.Query_Num(SB,A[i],R);
for(int i=1; i<=n; ++i) Ans+=1ll*B[i]*TA.Query_Num(SA,B[i]+1,R);
printf("%lld
",Ans);
for(int m=read(),opt,i,bef,nxt; m--; )
{
opt=read(), i=read(), nxt=read();
if(!opt)
{
bef=A[i];
Ans+=1ll*nxt*TB.Query_Num(SB,nxt,R)-1ll*bef*TB.Query_Num(SB,bef,R);
if(bef<nxt) Ans+=TB.Query_Sum(SB,bef,nxt-1);
else if(bef>nxt) Ans-=TB.Query_Sum(SB,nxt,bef-1);
TA.Delete(SA,bef), TA.Insert(SA,nxt), A[i]=nxt;
}
else
{
bef=B[i];
Ans+=1ll*nxt*TA.Query_Num(SA,nxt+1,R)-1ll*bef*TA.Query_Num(SA,bef+1,R);
if(bef<nxt) Ans+=TA.Query_Sum(SA,bef+1,nxt);
else if(bef>nxt) Ans-=TA.Query_Sum(SA,nxt+1,bef);
TB.Delete(SB,bef), TB.Insert(SB,nxt), B[i]=nxt;
}
printf("%lld
",Ans);
}
return 0;
}
B 仙人掌毒题(容斥/分治NTT 期望)
弃疗
C 珂学计树题(Burnside)
弃疗
考试代码
B
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define mod (998244353)
const int N=1e5+5,M=2e5+5;
int n,m,T,W,fa[N];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
int Get_fa(int x){
return x==fa[x]?x:fa[x]=Get_fa(fa[x]);
}
int main()
{
// freopen("ex_cactus2.in","r",stdin);
// freopen(".out","w",stdout);
n=read(), m=read(), T=read(), W=read();
for(int i=1; i<=n; ++i) fa[i]=i;
int ans=n;
for(int u,v; m--; )
{
u=read(), v=read();
if(Get_fa(u)!=Get_fa(v)) fa[fa[u]]=v, --ans;
printf("%d
",ans);
}
return 0;
}