A:
和某题很像,这题是带修改版本的
考虑把每条边
(u,v,w)
(
u
,
v
,
w
)
边权加到他连接的两点
u,v
u
,
v
上
当A,B中某人同时取了
u,v
u
,
v
,他获得
2w
2
w
的价值,对差值贡献
±2w
±
2
w
当A,B一人取了
u
u
,一人取了,各获得
w
w
,对差值贡献
发现将差值
/2
/
2
后和原来取边的情况等价
问题变成了
n
n
个点,取每个点有点权,A,B轮流取,A想最大化A-B,B反之
显然A,B会轮流取最大权的点
我们只要维护点权排序后奇数位置的权值和偶数位置的权值
带修改,修改=删除+插入
写一棵splay维护
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
ll ans;
inline void read(ll &x)
{
char c; while(!((c=getchar())>='0'&&c<='9'));
x=c-'0';
while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
x^=ans;
}
inline void up(int &a,const int &b){if(a<b)a=b;}
const int maxn = 210000;
int n,m,O;
int s[maxn];
int op[maxn][3],cnt;
struct Splay
{
int root;
int son[maxn][2],fa[maxn];
int siz[maxn];
ll sum[maxn][2];
int build(int l,int r)
{
int x=(l+r)>>1;
if(l==r) { siz[x]=1,sum[x][1]=s[x]; return x; }
if(l!=x) fa[son[x][0]=build(l,x-1)]=x;
if(x!=r) fa[son[x][1]=build(x+1,r)]=x;
pushup(x);
return x;
}
void pushup(int x)
{
int ls=siz[son[x][0]]&1;
sum[x][0]=sum[son[x][0]][0]+(ll)ls*s[x]+sum[son[x][1]][ls^1];
sum[x][1]=sum[son[x][0]][1]+(ll)(ls^1)*s[x]+sum[son[x][1]][ls];
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
}
void rot(int x,int &k)
{
int y=fa[x],z=fa[y];
if(y!=k) son[z][son[z][1]==y]=x;
else k=x;
fa[x]=z;
int l=son[y][1]==x;
fa[son[y][l]=son[x][!l]]=y;
fa[son[x][!l]=y]=x;
pushup(y);
}
void splay(int x,int &k)
{
for(;x!=k;rot(x,k))
{
int y=fa[x],z=fa[y];
if(y!=k) rot(((son[y][1]==x)^(son[z][1]==y))?x:y,k);
}
pushup(x);
}
int go(int x,int t)
{
while(son[x][t]) x=son[x][t];
return x;
}
void Del(int x)
{
splay(x,root);
int y=go(son[x][0],1);
if(y)
{
splay(y,son[x][0]);
root=fa[son[y][1]=son[x][1]]=y;
}
else fa[root=son[x][1]]=0;
pushup(root);
}
void Ins(int x)
{
son[x][0]=son[x][1]=0;
sum[x][0]=0,sum[x][1]=s[x];
siz[x]=1;
for(int p=root,l;;p=son[p][l])
{
l=s[p]<s[x];
if(!son[p][l])
{
fa[son[p][l]=x]=p;
splay(x,root);
break;
}
}
}
ll cal() { return (siz[root]&1)?sum[root][1]-sum[root][0]:sum[root][0]-sum[root][1]; }
}tr;
int main()
{
freopen("round.in","r",stdin);
freopen("round.out","w",stdout);
scanf("%d%d%d",&n,&m,&O);
tr.root=tr.build(1,n);
for(int i=1;i<=m;i++)
{
int type; scanf("%d",&type);
if(type==1)
{
ll u,v; int w; read(u),read(v); scanf("%d",&w);
ans=0;
++cnt,op[cnt][0]=u,op[cnt][1]=v,op[cnt][2]=w;
tr.Del(u); if(u!=v) tr.Del(v);
s[u]+=w,s[v]+=w;
tr.Ins(u); if(u!=v) tr.Ins(v);
}
else
{
ll k; read(k);
ans=0;
int u=op[k][0],v=op[k][1],w=op[k][2];
tr.Del(u); if(u!=v) tr.Del(v);
s[u]-=w,s[v]-=w;
tr.Ins(u); if(u!=v) tr.Ins(v);
}
ans=tr.cal()>>1;
printf("%lld\n",ans);
ans*=O;
}
return 0;
}
B:
突然就成了板子题?
设起点从左到右为,终点从左到右
b1,b2.....bn
b
1
,
b
2.....
b
n
因为不能路径相交,最终路径显然是
a1−>b1,a2−>b2,a3−>b3.....an−>bn
a
1
−
>
b
1
,
a
2
−
>
b
2
,
a
3
−
>
b
3.....
a
n
−
>
b
n
先考虑怎么求点
S
S
到,不经过障碍点的方案数
将
T
T
看作障碍点,设表示
S
S
到第个障碍点,中途不经过其他障碍点的方案数,转移的时候容斥一下,总方案数减不合法的,不合法的通过枚举遇到的第一个障碍点计算
f[i]=ways(S,i)−∑f[j]ways(j,i)
f
[
i
]
=
w
a
y
s
(
S
,
i
)
−
∑
f
[
j
]
w
a
y
s
(
j
,
i
)
然后设
M[i][j]
M
[
i
]
[
j
]
表示
ai
a
i
到
bj
b
j
不经过障碍点的方案数,根据某定理,这个
n∗n
n
∗
n
的矩阵的行列式就是路径两两不想交的总方案数
感受一下似乎就是个容斥
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxc = 210000;
const int maxn = 405;
const int mod = 998244353;
inline void add(int &a,const int &b){a+=b;if(a>=mod)a-=mod;}
inline void dec(int &a,const int &b){a-=b;if(a<0)a+=mod;}
int pw(int x,int k)
{
int re=1;
for(;k;k>>=1,x=(ll)x*x%mod) if(k&1)
re=(ll)re*x%mod;
return re;
}
int inv(int x){ return pw(x,mod-2); }
int s[maxc],invs[maxc];
void pre()
{
s[0]=1; for(int i=1;i<maxc;i++) s[i]=(ll)s[i-1]*i%mod;
invs[maxc-1]=inv(s[maxc-1]);
for(int i=maxc-2;i>=0;i--) invs[i]=(ll)invs[i+1]*(i+1)%mod;
}
int C(int i,int j){ return i>=j?(ll)s[i]*invs[j]%mod*invs[i-j]%mod:0; }
int n,m,p,q;
struct point
{
int x,y;
int cal(point z)
{
if(z.x<x||z.y<y) return 0;
return C(z.x-x+z.y-y,z.x-x);
}
}st[maxn],ed[maxn],pi[maxn];
inline bool cmp(const point x,const point y){ return x.x==y.x?x.y<y.y:x.x<y.x; }
namespace Gauss
{
int n;
int a[maxn][maxn];
int Solve()
{
for(int i=1;i<n;i++)
{
if(!a[i][i])
{
int k=0;
for(int j=i+1;j<=n;j++) if(a[j][i]) { k=j;break; }
if(k)
{
for(int j=i;j<=n;j++) swap(a[i][j],a[k][j]);
}
else continue;
}
int ii=inv(a[i][i]);
for(int j=1;j<=n;j++) if(a[j][i]&&j!=i)
{
int k=(ll)ii*a[j][i]%mod;
for(int l=i;l<=n;l++) dec(a[j][l],(ll)a[i][l]*k%mod);
}
}
int ans=1;
for(int i=1;i<=n;i++) ans=(ll)ans*a[i][i]%mod;
return ans;
}
}
int f[maxn];
int main()
{
freopen("canal.in","r",stdin);
freopen("canal.out","w",stdout);
pre();
scanf("%d%d%d%d",&n,&m,&p,&q);
for(int i=1;i<=p;i++) st[i].x=0,scanf("%d",&st[i].y);
for(int i=1;i<=p;i++) ed[i].x=n,scanf("%d",&ed[i].y);
for(int i=1;i<=q;i++) scanf("%d%d",&pi[i].x,&pi[i].y);
sort(st+1,st+p+1,cmp);
sort(ed+1,ed+p+1,cmp);
sort(pi+1,pi+q+1,cmp);
Gauss::n=p;
for(int i=1;i<=p;i++)
{
for(int j=1;j<=q;j++)
{
f[j]=st[i].cal(pi[j]);
for(int k=1;k<j;k++) dec(f[j],(ll)f[k]*pi[k].cal(pi[j])%mod);
}
for(int j=1;j<=p;j++)
{
int &temp=Gauss::a[i][j];
temp=st[i].cal(ed[j]);
for(int k=1;k<=q;k++) dec(temp,(ll)f[k]*pi[k].cal(ed[j])%mod);
}
}
printf("%d\n",Gauss::Solve());
return 0;
}
C:
Simpson积分能拿50pt
求凸多边形和所有圆并面积,圆并面积,凸多边形面积
算面积格林公式变二重积分,然后找每条线段,每个圆的圆弧,在边界上的部分,叉积积分一下算面积
反正我不会