P5358 [SDOI2019]快速查询
整体打标记,注意顺序即可
P5361 [SDOI2019]热闹的聚会与尴尬的聚会
第一问导出子图的最小点度数尽可能大§:每次删去度数最小的点,更新其它点的度数,找到剩下所有人点度数的最小值最大的一个位置
第二问尽可能大的独立集(q):每次选出度数最小的点,删去它和它相连的点,然后继续选度数最小的,直到没得选
这种是求最大独立集(NPC问题)的一种近似算法,这道题目中可以证
(
p
+
1
)
(
q
+
1
)
≥
n
+
1
(p+1)(q+1)\ge n+1
(p+1)(q+1)≥n+1,因为求独立集的时候每次删掉的点的度数+1之和为n,那么最大值+1乘上次数一定大于n
代码
P5363 [SDOI2019]移动金币
把两个金币之间的空格数当成放在一个台阶上的石子个数,那么左移一个金币相当于把若干个石子向下移动一个台阶
那么就是经典的阶梯博弈了,后手必胜的局面是偶数编号的台阶上石子个数异或和为0,题目问存在多少中这样的初始状态
因为直接dp复杂度过高,因为有异或操作,考虑二进制每一位的情况,如果偶数位置异或和为0,意味着二进制下每一位,偶数位置都有偶数个1,这样我们就可以dp了,设 f i , j f_{i,j} fi,j表示二进制下从高位到低位计算到了第 i 位,剩余石子 j 个的方案数,我们可以枚举 2k 表示放 2k 个石子在偶数位置上转移即可
剩下的石子放在奇数位置,利用插板法计算即可
代码
ybtoj761. 「启发式合并」最长路径
利用线段树下标表示深度,值表示到根的距离
每次先计算轻儿子,清空线段树,然后计算重儿子不清空线段树,再走一次轻儿子计算贡献并加入到线段树中
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,ll> PIL;
const int maxn=1e6+5;
const ll inf=1e17;
const ll mod=998244353;
int n,ql[maxn],qr[maxn];
vector <PIL> G[maxn];
int siz[maxn],son[maxn];
int mxdep[maxn],dep[maxn];
ll dis[maxn];
void dfs(int u,int fa)
{
siz[u]=1; mxdep[u]=dep[u]=dep[fa]+1;
for(auto to:G[u])
{
int v=to.first;
dis[v]=dis[u]+to.second;
dfs(v,u);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v]) son[u]=v;
mxdep[u]=max(mxdep[u],mxdep[v]);
}
}
ll tr[maxn<<2];
#define lson now<<1
#define rson now<<1|1
void change(int now,int l,int r,int pos,ll val)
{
if(l==r)
{
tr[now]=val;
return;
}
int mid=l+r>>1;
if(pos<=mid) change(lson,l,mid,pos,val);
else change(rson,mid+1,r,pos,val);
tr[now]=max(tr[lson],tr[rson]);
}
void update(int now,int l,int r,int pos,ll val)
{
if(l==r)
{
tr[now]=max(tr[now],val);
return;
}
int mid=l+r>>1;
if(pos<=mid) update(lson,l,mid,pos,val);
else update(rson,mid+1,r,pos,val);
tr[now]=max(tr[lson],tr[rson]);
}
ll query(int now,int l,int r,int L,int R)
{
if(l>=L && r<=R) return tr[now];
int mid=l+r>>1;
ll res=-inf;
if(L<=mid) res=max(res,query(lson,l,mid,L,R));
if(mid<R) res=max(res,query(rson,mid+1,r,L,R));
return res;
}
ll ans[maxn];
void calc(int u,int fa)
{
ans[fa]=max(ans[fa],query(1,1,n,max(1,ql[fa]-dep[u]+2*dep[fa]),min(n,qr[fa]-dep[u]+2*dep[fa]))+dis[u]-2*dis[fa]);
for(auto to:G[u])
calc(to.first,fa);
}
void add(int u)
{
update(1,1,n,dep[u],dis[u]);
for(auto to:G[u])
add(to.first);
}
void solve(int u)
{
for(auto to:G[u])
{
int v=to.first;
if(v==son[u]) continue;
solve(v);
for(int i=dep[v];i<=mxdep[v];i++)
change(1,1,n,i,-inf);
}
if(son[u]) solve(son[u]);
ans[u]=max(ans[u],query(1,1,n,max(1,dep[u]+ql[u]),min(n,dep[u]+qr[u]))-dis[u]);
update(1,1,n,dep[u],dis[u]);
for(auto to:G[u])
{
int v=to.first;
if(v==son[u]) continue;
calc(v,u); add(v);
}
}
int main()
{
freopen("watchdog.in","r",stdin);
freopen("watchdog.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&ql[i],&qr[i]),ans[i]=-1;
int x; ll z;
for(int i=2;i<=n;i++)
{
scanf("%d%lld",&x,&z);
G[x].push_back(make_pair(i,z));
}
dfs(1,0);
for(int i=1;i<=(n<<2);i++) tr[i]=-inf;
solve(1);
for(int i=1;i<=n;i++) ans[i]=(ans[i]%mod+mod)%mod;
ll res=0,bas=1;
for(int i=n;i;i--)
res=(res+bas*ans[i]%mod)%mod,bas=bas*23333ll%mod;
printf("%lld",res);
return 0;
}