今天是水题专场
T1 扩散
感觉这种要么就是二分答案网络流,要么就是最小生成树,(随便口胡的),树德保留节目了属于是。
分析
简简单单一眼最小生成树(又是),边权就是两个点之间存在公共区域的时间,这个距离随便找一找规律就好算了。这里直接给结论了\(w(x1,y1,x2,y2)=\) \(\frac{abs(x1-x2)+abs(y1-y2)}{2}\)然后建所有可能的边,最后再最小生成树就行,(听说二分也能做?
Code
点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define int long long
using namespace std;
const int maxn=100;
inline int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')f=-1;
c=getchar();
}
while('0'<=c&&c<='9')
{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*f;
}
int n;
int abs1(int x){return x>0?x:-x;}
int calc(int x1,int y1,int x2,int y2){return ceil((1.0*abs1(x1-x2)+1.0*abs1(y1-y2))/2);}
int x[maxn],y[maxn];
struct Edge{int u,v,w;}E[5000];int tote=0;
bool cmp(Edge a,Edge b){return a.w<b.w;}
int f[100];int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
signed main()
{
n=read();
for(int i=1;i<=n;i++)x[i]=read(),y[i]=read(),f[i]=i;;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
E[++tote].u=i,E[tote].v=j,E[tote].w=calc(x[i],y[i],x[j],y[j]);
sort(E+1,E+tote+1,cmp);
int cnt=0;int ans=-1;
for(int i=1;i<=tote;i++)
{
if(cnt==n-1)break;
int x=find(E[i].u),y=find(E[i].v);
if(x==y)continue;
f[x]=y;
ans=max(ans,E[i].w);
}
printf("%lld",ans);
return 0;
}
T2 树链剖分板子
没有什么好说的,就浅浅地总结一下
\(dfs1\):求出基本信息:深度、父亲、子树大小、重儿子编号
\(dfs2\):求出\(dfn\)序、对应节点的权值、当前节点的重链顶端节点
\(query\):求出从\(l\)到\(r\)的路径上面的信息
实现方法就是只要当前两个节点的顶端节点不同,就让顶端节点深度更深的点跳到它所在重链的顶端,并且统计这一条链的答案,直到\(l、r\)在一条重链上面。最后再把深度深的点跳到浅的点上,再统计这一小节的答案。
画个图就很轻易地知道这时候每个子树的\(dfn\)序是一定连续的,所以就可以用线段树来维护区间最值
Code
点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#define int long long
#define MAXN 200000
using namespace std;
inline int read()
{
long long s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
s=(s<<3)+(s<<1)+(ch^48);
ch=getchar();
}
return s*w;
}
template <typename T>void wr(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) wr(x/10);
putchar(x%10^'0');
return;
}
int n,m;
long long val[MAXN];
struct Edge{int u,v;int nex;}tr[4*MAXN];
int head[MAXN],tote;
void add(int u,int v)
{
tr[++tote].u=u;
tr[tote].v=v;
tr[tote].nex=head[u];
head[u]=tote;
tr[++tote].u=v;
tr[tote].v=u;
tr[tote].nex=head[v];
head[v]=tote;
}
int fa[MAXN],siz[MAXN],dep[MAXN],son[MAXN];
void dfs1(int x,int f)
{
dep[x]=dep[f]+1;siz[x]=1;fa[x]=f;
int maxsonsize=-1;
for(int i=head[x];i;i=tr[i].nex)
{
int v=tr[i].v;
if(v==f)continue;
dfs1(v,x);
siz[x]+=siz[v];
if(siz[v]>maxsonsize)maxsonsize=siz[v],son[x]=v;
}
}
int id[MAXN],num;long long w[MAXN];int top[MAXN];
void dfs2(int x,int TOP)
{
top[x]=TOP;id[x]=++num;w[id[x]]=val[x];
if(!son[x])return;
dfs2(son[x],TOP);
for(int i=head[x];i;i=tr[i].nex)
{
int v=tr[i].v;
if(v==fa[x]||v==son[x])continue;
dfs2(v,v);
}
}
struct Node{int l,r;long long val;long long tag;long long Max;}a[4*MAXN];
long long calc(int x){return a[x].val+(a[x].r-a[x].l+1)*a[x].tag;}
void down(int x)
{
a[x<<1].tag+=a[x].tag;
a[(x<<1)|1].tag+=a[x].tag;
a[x].val=calc(x);
a[x].tag=0;
a[x].Max=max(a[x<<1].Max,a[(x<<1)|1].Max);
}
void build(int x,int l,int r)
{
a[x].l=l;a[x].r=r;
if(l==r){a[x].val=a[x].Max=w[l];return;}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build((x<<1)|1,mid+1,r);
a[x].val=calc(x<<1)+calc((x<<1)|1);
a[x].Max=max(a[x<<1].Max,a[(x<<1)|1].Max);
}
void update(int x,int l,int r,int k)
{
if(a[x].l>=l&&a[x].r<=r){a[x].tag+=k,a[x].Max=k;return;}
down(x);
int mid=(a[x].l+a[x].r)>>1;
if(mid>=l)update(x<<1,l,r,k);
if(mid<r)update((x<<1)|1,l,r,k);
a[x].val=calc(x<<1)+calc((x<<1)+1);
a[x].Max=max(a[x<<1].Max,a[(x<<1)|1].Max);
}
void change(int x,int pos,int v)
{
if(a[x].l==a[x].r){a[x].val=v,a[x].Max=v;return;}
int mid=(a[x].l+a[x].r)>>1;
if(pos<=mid)change(x<<1,pos,v);
else change(x<<1|1,pos,v);
a[x].val=calc(x<<1)+calc(x<<1|1);
a[x].Max=max(a[x<<1].Max,a[x<<1|1].Max);
}
long long query(int x,int l,int r)
{
if(a[x].l>=l&&a[x].r<=r){return calc(x);}
down(x);
int mid=(a[x].l+a[x].r)>>1;
long long ret=0;
if(mid>=l)ret+=query(x<<1,l,r);
if(mid<r)ret+=query((x<<1)|1,l,r);
a[x].val=calc(x<<1)+calc((x<<1)|1);
a[x].Max=max(a[x<<1].Max,a[(x<<1)|1].Max);
return ret;
}
int querymax(int x,int l,int r)
{
if(a[x].l>=l&&a[x].r<=r){return a[x].Max;}
down(x);
int mid=(a[x].l+a[x].r)>>1;int ans=-2147483640;
if(mid>=l)ans=max(querymax(x<<1,l,r),ans);
if(mid<r)ans=max(querymax((x<<1)|1,l,r),ans);
return ans;
}
long long query_rootsum(int l,int r)
{
long long ret=0;
while(top[l]!=top[r])
{
if(dep[top[l]]<dep[top[r]])swap(l,r);
ret+=query(1,id[top[l]],id[l]);
l=fa[top[l]];
}
if(dep[l]>dep[r])swap(l,r);
ret+=query(1,id[l],id[r]);
return ret;
}
long long query_max(int l,int r)
{
long long ans=-2147483640;
while(top[l]!=top[r])
{
if(dep[top[l]]<dep[top[r]])swap(l,r);
ans=max(querymax(1,id[top[l]],id[l]),ans);
l=fa[top[l]];
}
if(dep[l]>dep[r])swap(l,r);
ans=max(querymax(1,id[l],id[r]),ans);
return ans;
}
string s;
signed main(){
n=read();
for(int i=1;i<n;i++)
{
int u,v;
u=read(),v=read();
add(u,v);
}
for(int i=1;i<=n;++i) val[i]=read();
dfs1(1,0);
dfs2(1,1);
build(1,1,n);
int q=read();
for(int i=1;i<=q;i++)
{
cin>>s;
if(s[0]=='C')
{
int x;
long long y;
x=read(),y=read();
change(1,id[x],y);
}
else if(s=="QMAX")
{
int x;long long y;
x=read(),y=read();
wr(query_max(x,y));
printf("\n");
}
else if(s=="QSUM")
{
int x,y;
x=read(),y=read();
wr(query_rootsum(y,x));
printf("\n");
}
}
return 0;
}
T3佳佳的数学作业
一眼矩阵,可是一开始遇到了一些困难,比如转移矩阵里面必须是常值,但是后面经过一系列推导和转化,还是把感觉很妙的一个解给写出来了,马上就要去跑步了,推导的过程明早重点来写,先贴代码把
Code
点击查看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int maxn=1e5;
struct Matrix{int n,m,a[10][10];Matrix(){memset(a,0,sizeof a);};}sup[5];
int N,M;
Matrix operator *(Matrix a,Matrix b)
{
Matrix tmp;tmp.n=a.n,tmp.m=b.m;
for(int i=1;i<=a.n;i++)
for(int j=1;j<=b.m;j++)
{
int c=0;
for(int k=1;k<=a.m;k++) c=(c%M+(a.a[i][k]%M)*(b.a[k][j]%M))%M;
tmp.a[i][j]=c;
}
return tmp;
}
Matrix base(int x)
{
Matrix tmp;tmp.n=tmp.m=x;
for(int i=1;i<=x;i++)tmp.a[i][i]=1;
return tmp;
}
Matrix Mpower(Matrix a,int b)
{
Matrix ans=base(a.n);
while(b)
{
if(b&1)ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
void pre()
{
sup[1].m=3,sup[1].n=3;
sup[1].a[1][1]=1,sup[1].a[1][2]=1;
sup[1].a[2][2]=1,sup[1].a[2][3]=1;
sup[1].a[3][2]=1;
sup[2].m=sup[2].n=5;
sup[2].a[1][1]=1,sup[2].a[1][2]=1,sup[2].a[1][3]=-1;
sup[2].a[2][2]=1;
sup[2].a[3][3]=1;sup[2].a[3][4]=1;
sup[2].a[4][4]=1,sup[2].a[4][5]=1;
sup[2].a[5][4]=1;
}
void print(Matrix a)
{
for(int i=1;i<=a.n;i++)
{
for(int j=1;j<=a.m;j++)
printf("%lld ",a.a[i][j]);
printf("\n");
}
}
signed main()
{
scanf("%lld%lld",&N,&M);
pre();
Matrix ans1;ans1.n=3,ans1.m=1;
ans1.a[1][1]=0,ans1.a[2][1]=1,ans1.a[3][1]=0;
ans1=Mpower(sup[1],N)*ans1;
Matrix ans2;ans2.n=5,ans2.m=1;
ans2.a[1][1]=0,ans2.a[2][1]=ans1.a[1][1],ans2.a[3][1]=0,ans2.a[4][1]=1,ans2.a[5][1]=0;
ans2=Mpower(sup[2],N)*ans2;
printf("%lld",(ans2.a[1][1]+M)%M);
return 0;
}
T4中位数
说实话一开始真的没什么思路的,但是想到了对于当前这个位置统计它前后大于和小于它的是否相等,但实在没有想到用\(+1 -1\)的方式来表示,还可以用查分的方式来维护区间和
Code
点击查看代码
#include<iostream>
#include<cstdio>
#include<unordered_map>
#define ll long long
using namespace std;
int ans,wei,n,b,a[110000],tot,sum[110000];
unordered_map<int,int>mp;
int main(){
// freopen("mid.in","r",stdin);
// freopen("mid.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>b;
for(register int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==b)wei=i;
}
int big=0,small=0;
for(register int i=wei;i>0;i--){
if(a[i]>b)big++;
else{
if(a[i]<b)small++;
}
int delta=big-small;
//if(delta==0)ans++;
if(mp.find(delta)==mp.end()){
mp[delta]=++tot;
}
sum[mp[delta]]++;
}
big=0;
small=0;
for(register int i=wei;i<=n;i++){
if(a[i]>b)big++;
else{
if(a[i]<b)small++;
}
int delta=big-small;
if(mp.find(-delta)==mp.end())continue;
ans+=sum[mp[-delta]];
}
cout<<ans;
return 0;
}
/*
7 4
5 7 2 4 3 1 6
9 5
9 8 1 2 5 4 3 6 7
*/