TJOI2015 D2
T1
给一颗树,每次给出 A 、B ,求 A -> B 的路径上 max{aj - ai} (i 先于 j 经过),然后将A -> B 的路径上的点全部加上 v
裸的树链剖分,主要是线段树最大最小值的合并操作,线段树维护区间最大值、最小值、从左到右的最大差和从右到左的最大差,先求得两点的lca,再分别计算 x -> lca 和 lca -> y ,注意顺序不能写反。每次要询问完后,再修改,不然会Wa掉。
//代码能力还是不够,写了一天。。。
复杂度:O(Nlog^2N)
需要的知识:链剖
T2
看到这道题想到的肯定是状压DP,先预处理出每一种状态,然后验证当前状态合不合法,再求得每种状态能否转移到另一种状态。
得到状态转移方程
F[i, j] = ∑F[i−1,k] (其中 a[j,k]=1 , 即 k 状态能转移到 j 状态) //写矩乘的时候写成了这样,-_-
这样的复杂度是 O(n * 2^m * 2^m),要T
然后发现每种转移都是一样的
然后设一个 tot * tot(状态数)的矩阵 a , aij 表示状态 j 能转移到状态 i ,tot * 1 的矩阵 b 表示初始状态,即F[0,0],然后矩阵快速幂
复杂度:O(logN * (2^m)^3)
需要的知识:状压dp,矩阵快速幂
T3
神一样的题(╯▽╰)
找到规律 ans = n*(n+1)/(4n-2)
证明:YYY第一定理
//其实不会啦~~
需要的知识:数学
贴代码
T1 bzoj3999
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<ctime>
#include<cmath>
#define N 50005
#define INF 100000000000
#define LL long long
using namespace std;
int n,m,Size,tot,x,y,k;LL c,minn,maxx,ans;
int first[N],next[N<<1],to[N<<1];
int father[N],son[N],d[N],w[N],top[N],size[N];
LL mx[N<<2],mn[N<<2],delt[N<<2][2],f[N<<2];
int a[N],b[N],p[N];
int get_int()
{
int ret=0;char c=getchar();
for (;c<'0'||c>'9';c=getchar());
for (;c>='0'&&c<='9';c=getchar())
ret=(ret<<1)+(ret<<3)+c-'0';
return ret;
}
void inser(int x,int y)
{
Size++;
next[Size]=first[x];
first[x]=Size;
to[Size]=y;
}
void dfs1(int x)
{
size[x]=1;
for (int i=first[x];i;i=next[i])
{
int y=to[i];
if (y!=father[x])
{
father[y]=x;
d[y]=d[x]+1;
dfs1(y);
if (size[y]>size[son[x]])
son[x]=y;
size[x]+=size[y];
}
}
}
void dfs2(int x,int tp)
{
top[x]=tp;
w[x]=++tot;
if (son[x]) dfs2(son[x],tp);
for (int i=first[x];i;i=next[i])
{
int y=to[i];
if (y!=father[x]&&y!=son[x])
dfs2(y,y);
}
}
void push_down(int v)
{
if (!f[v]) return;
int lc=v<<1,rc=v<<1|1;
f[lc]+=f[v];
f[rc]+=f[v];
mx[lc]+=f[v];
mx[rc]+=f[v];
mn[lc]+=f[v];
mn[rc]+=f[v];
f[v]=0;
}
void update(int v)
{
int lc=v<<1,rc=v<<1|1;
mx[v]=max(mx[lc],mx[rc]);
mn[v]=min(mn[lc],mn[rc]);
delt[v][0]=max(max(delt[lc][0],delt[rc][0]),mx[rc]-mn[lc]);
delt[v][1]=max(max(delt[lc][1],delt[rc][1]),mx[lc]-mn[rc]);
}
void build(int v,int l,int r)
{
if (l==r)
{
mx[v]=mn[v]=b[l];
return;
}
int mid=(l+r)>>1;
build(v<<1,l,mid);
build(v<<1|1,mid+1,r);
update(v);
}
void init()
{
int x,y;
n=get_int();
for (int i=1;i<=n;i++) a[i]=get_int();
for (int i=1;i<n;i++)
{
x=get_int();y=get_int();
inser(x,y);
inser(y,x);
}
dfs1(1);
dfs2(1,1);
for (int i=1;i<=n;i++) b[w[i]]=a[i];
build(1,1,n);
}
void modify(int v,int l,int r)
{
if (x<=l&&r<=y)
{
f[v]+=c;
mn[v]+=c;
mx[v]+=c;
return;
}
int mid=(l+r)>>1;
push_down(v);
if (x<=mid) modify(v<<1,l,mid);
if (mid<y) modify(v<<1|1,mid+1,r);
update(v);
}
void add(int v,int u)
{
int f1=top[v],f2=top[u];
while (f1!=f2)
{
if (d[f1]<d[f2])
{
swap(f1,f2);
swap(v,u);
}
x=w[f1],y=w[v],modify(1,1,n);
v=father[f1],f1=top[v];
}
if (d[v]<d[u]) swap(v,u);
x=w[u],y=w[v],modify(1,1,n);
}
int lca(int x,int y)
{
while (top[x]!=top[y])
{
if (d[top[x]]<d[top[y]]) swap(x,y);
x=father[top[x]];
}
return d[x]<d[y] ? x : y;
}
void ask(int v,int l,int r)
{
if (x<=l&&r<=y)
{
ans=max(max(ans,delt[v][k]),mx[v]-minn);
maxx=max(mx[v],maxx);
minn=min(mn[v],minn);
return;
}
int mid=(l+r)>>1;
push_down(v);
if (k){
if (mid<y) ask(v<<1|1,mid+1,r);
if (x<=mid) ask(v<<1,l,mid);
}else {
if (x<=mid) ask(v<<1,l,mid);
if (mid<y) ask(v<<1|1,mid+1,r);
}
update(v);
}
void query(int v,int u)
{
int z=lca(v,u);
minn=INF,maxx=ans=0,k=1;
while (top[v]!=top[z])
{
x=w[top[v]],y=w[v],ask(1,1,n);
v=father[top[v]];
}
x=w[z],y=w[v],ask(1,1,n);
tot=k=0;
while (top[u]!=top[z])
{
p[++tot]=w[u];p[++tot]=w[top[u]];
u=father[top[u]];
}
if (u^z) p[++tot]=w[u],p[++tot]=w[z];
for (int i=tot;i;i-=2)
x=p[i],y=p[i-1],ask(1,1,n);
}
int main()
{
int v,u;
init();
m=get_int();
for (int i=1;i<=m;i++)
{
v=get_int();u=get_int();c=get_int();
query(v,u);
printf("%lld\n",ans);
add(v,u);
}
return 0;
}
T2 bzoj4000
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<ctime>
#include<cmath>
#define LL long long
using namespace std;
const LL M=(LL)(1ll<<32ll) - 1;
int n,m,k,p,tot;
int b[3],c[64];
LL a[64][64],ret[64][64],t[64][64];
bool judge(int x)
{
for (int i=0,t=x;i<m;t>>=1,i++)
if (t&1)
{
if (k>=i)
if (x&(b[1]>>(k-i))) return 0;
if (k<i)
if (x&(b[1]<<(i-k))) return 0;
}
return 1;
}
int check(int x,int y)
{
for (int i=0,t=x;i<m;t>>=1,i++)
if (t&1)
{
if (k>=i)
if (y&(b[2]>>(k-i))) return 0;
if (k<i)
if (y&(b[2]<<(i-k))) return 0;
}
for (int i=0,t=y;i<m;t>>=1,i++)
if (t&1)
{
if (k>=i)
if (x&(b[0]>>(k-i))) return 0;
if (k<i)
if (x&(b[0]<<(i-k))) return 0;
}
return 1;
}
void init()
{
int x;
scanf("%d%d",&n,&m);
scanf("%d%d",&p,&k);
k=p-k-1;
for (int i=0;i<3;i++)
for (int j=0;j<p;j++)
{
scanf("%d",&x);
b[i]=b[i]<<1|x;
}
b[1]^=(1<<k);
for (int i=0;i<(1<<m);i++)
if (judge(i)) c[tot++]=i;
for (int i=0;i<tot;i++)
for (int j=0;j<tot;j++)
a[j][i]=check(c[i],c[j]);
}
LL mult(LL m,LL n)
{
LL a=m>>1,x=m-a,b=n>>1,y=n-b;
return ((a*b)&M)+((a*y)&M)+((b*x)&M)+((x*y)&M);
}
void mul(LL a[][64],LL b[][64])
{
for (int i=0;i<tot;i++)
for (int j=0;j<tot;j++)
{
t[i][j]=0;
for (int k=0;k<tot;k++)
t[i][j]=(t[i][j]+mult(a[i][k],b[k][j]))&M;
}
for (int i=0;i<tot;i++)
for (int j=0;j<tot;j++)
a[i][j]=t[i][j];
}
void ksm(int b)
{
for (int i=0;i<tot;i++) ret[i][i]=1;
for (;b;b>>=1,mul(a,a))
if (b&1) mul(ret,a);
}
int main()
{
init();
ksm(n);
LL ans=0;
for (int i=0;i<tot;i++)
ans=(ans+ret[i][0])&M;
cout<<ans<<endl;
return 0;
}
T3 bzoj4001
#include<cstdio>
int main(){
double n;
scanf("%lf",&n);
printf("%0.9f",n*(n+1)/(4*n-2));
return 0;
}
YYY 就是神~