[NOIP2018模拟赛10.16]手残报告
[NOIP2018模拟赛10.16]手残报告
闲扯
炉石乱斗模式美滋滋啊,又颓到好晚...
上来T2先敲了树剖,看T1发现是个思博DP,然后没过大样例,写个暴力发现还是没过大样例!?才发现理解错题意了,真是太菜了
然后看T3发现又要树剖,想了想发现边双缩点似乎能做...结果码来码去比赛临近结束才搞完,赶紧交代码.
但是那台机子上的Chrome似乎是个假的,打开什么网页都巨慢,最后T1手残交了份一开始的错误代码上去,T2T3生死未卜
结果40+0+0 T1错代码居然还有40?!数据这么水...再交遍正确代码一A
T2T3下午检查的时候发现树剖犯了SB错误 还是记在了我错误笔记上的...太菜了
下午改T3边双缩点居然A了std是圆方树的T3?!还跑了rank2?! (虽然现在xxzh巨佬是rank2
而且第一发交的树剖还是有错的.这数据无力吐槽了
晚上码T2,结果至今卡死在70 TLE三点,然而那台老年机都跑过了我也不知道咋回事
T1 轻功
分析
思博DP,\(f[i][j]\)表示当前使用第\(j\)轻功种走到\(i\)这个点的最短时间
\(f[i][j]=min(f[i-a[j]][p]+v[j]+[j!=p] \times w)\)
预处理一下非法情况就好了
代码
/*
code by RyeCatcher
*/
inline char gc(){
static char buf[SIZE],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
}
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
}
const int maxn=505;
const ll inf=1e17;
int n,k,q;
ll v[maxn];
int a[maxn];
bool fob[maxn][105];
bool ok[maxn][105];
ll w,f[maxn][105];
namespace bf{
ll ans=inf;
void dfs(int now,int kk,ll c){
if(ok[now][kk])return ;
if(now>n)return ;
if(now==n){
ans=min(ans,c);
return ;
}
for(ri i=1;i<=k;i++){
if(ok[now+a[i]][i])continue;
if(i==kk){
dfs(now+a[i],i,c+v[i]);
}
else dfs(now+a[i],i,c+v[i]+w);
}
return ;
}
void main(){
for(ri i=1;i<=k;i++)dfs(0,i,0);
printf("%lld\n",ans);
return ;
}
}
int main(){
int x,y;
FO(qinggong);
read(n),read(k),read(w);
for(ri i=1;i<=k;i++){
read(a[i]),read(v[i]);
}
memset(fob,0,sizeof(fob));
memset(ok,0,sizeof(ok));
read(q);
while(q--){
read(x),read(y);
fob[x][y]=1;
}
for(ri i=0;i<=n;i++){
for(ri j=1;j<=k;j++)f[i][j]=inf;
}
int t=0;
for(ri i=0;i<=k;i++)if(!fob[0][i])f[0][i]=0;
for(ri i=0;i<=n;i++){
for(ri j=1;j<=k;j++){
bool flag=0;
if(i>=a[j]){
for(ri o=i-a[j];o<=i;o++)if(fob[o][j]){flag=1;break;}
if(flag)ok[i][j]=1;
}
}
}
if(n<=15){bf::main();return 0;}
for(ri i=1;i<=n;i++){
for(ri j=1;j<=k;j++){
if(ok[i][j])continue;
for(ri p=1;p<=k;p++){
if(i>=a[j]){
if(ok[i-a[j]][p])continue;
f[i][j]=min(f[i][j],1ll*(f[i-a[j]][p]+v[j]+((j==p)?0:w)));
}
}
}
}
ll ans=inf;
for(ri i=1;i<=k;i++)ans=min(ans,f[n][i]);
if(ans==inf)puts("-1");
else printf("%lld\n",ans);
return 0;
}
T2 开荒
精巧的树剖,询问时将所有点按\(dfs\)序排序
钦定当前公共\(LCA\) \(x\),对于排序后第\(i\)个点和\(i-1\)号点的LCA \(y\),如果\(y\)在\(x\)子树中,那么计算\(i\)到\(y\)路径贡献(不包括\(y\)),否则根据DFS序排序后的性质, \(y\)就比\(x\)高明,将\(y\)设为公共\(LCA\),计算\(fa[x]\)到\(i\)号点路径贡献
然后一直卡在70分。。。以后能用树状数组再也不用线段树了
/*
code by RyeCatcher
*/
inline char gc(){
static char buf[SIZE],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
}
const int maxn=200005;
const int inf=0x7fffffff;
int n,q;
int que[10000005],cnt=0;
struct Edge{
int ne,to;
}edge[maxn<<1];
int h[maxn],num_edge=1;
inline void add_edge(int f,int to){
edge[++num_edge].ne=h[f];
edge[num_edge].to=to;
h[f]=num_edge;
}
ll w[maxn];
int dep[maxn],fa[maxn],dfn[maxn],top[maxn],size[maxn],son[maxn],tot=0,rnk[maxn];
void dfs_1(int now){
int v;
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(v==fa[now]||dep[v])continue;
fa[v]=now,dep[v]=dep[now]+1;
dfs_1(v);
size[v]+=size[now];
if(!son[now]||size[v]>size[son[now]])son[now]=v;
}
return ;
}
void dfs_2(int now,int t){
int v;
top[now]=t,dfn[now]=++tot,rnk[tot]=now;
if(!son[now])return ;
dfs_2(son[now],t);
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(v==fa[now]||v==son[now]||dfn[v])continue;
dfs_2(v,v);
}
}
int L,R,t;
ll dta,ans=0;
ll s[maxn<<2];
inline void add(){for(;t<=n;t+=t&(-t))s[t]+=dta;}
inline ll sum(int x){ll tmp=0;for(;x;x-=x&(-x))tmp+=s[x];return tmp;}
inline ll calc(int l,int r) {return sum(r)-sum(l-1);}
bool cmp(int a,int b){return dfn[a]<dfn[b];}
inline int get_lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])std::swap(x,y);
x=fa[top[x]];
}
if(dep[x]>dep[y])return y;
return x;
}
inline void query_path(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])std::swap(x,y);
L=dfn[top[x]],R=dfn[x];
ans+=calc(L,R);
x=fa[top[x]];
}
if(dep[x]>dep[y])std::swap(x,y);
L=dfn[x],R=dfn[y];
ans+=calc(L,R);
return ;
}
inline void solve(){
int x,y;
if(cnt==1){
printf("%lld\n",w[que[1]]);
return ;
}
x=que[1],ans=w[x];
for(ri i=2;i<=cnt;i++){
y=get_lca(que[i],que[i-1]);
if(dfn[x]<=dfn[y]){
query_path(y,que[i]);
ans-=w[y];
}
else{
query_path(fa[x],que[i]);
x=y;
}
}
printf("%lld\n",ans);
return ;
}
int main(){
int x,y;
FO(kaihuang);
//freopen("ex_kaihuang.in","r",stdin);
read(n),read(q);
for(ri i=1;i<=n;i++)read(w[i]);
for(ri i=1;i<n;i++){
read(x),read(y);
add_edge(x,y);
add_edge(y,x);
}
dep[1]=1,fa[1]=0;
dfs_1(1);
dfs_2(1,1);
for(ri i=1;i<=n;i++){
t=dfn[i],dta=w[i];
add();
}
char opt[10];
while(q--){
scanf("%s",opt);
if(opt[0]=='Q'){
read(x);
cnt=0;
while(x){
que[++cnt]=x;
read(x);
}
if(cnt==0){
puts("0");
continue;
}
std::sort(que+1,que+1+cnt,cmp);
cnt=std::unique(que+1,que+1+cnt)-(que+1);
solve();
}
else{
read(x),read(y);
t=dfn[x],dta=y-w[x],w[x]=y;
add();
}
//puts("fafa");
}
return 0;
}
T3 跑商
分析
考场上Tarjan还有行写反了G
标算圆方树不会啊,我这个边双感觉就是个挺靠谱的假算法,边双缩点后形成的的树进行树链剖分,缩的点用一个\(multiset\)动态维护点内的最小值,查询直接树剖
代码
inline char gc(){
static char buf[SIZE],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,SIZE,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
template <class T>inline void read(T &x){
x=0;int ne=0;char c;
while((c=gc())>'9'||c<'0')ne=c=='-';x=c-48;
while((c=gc())>='0'&&c<='9')x=(x<<3)+(x<<1)+c-48;x=ne?-x:x;return ;
}
const int maxn=200005;
const int inf=0x7fffffff;
int n,m,q;
ll w[maxn],val[maxn];
struct Edge{
int ne,to;
}edge[maxn<<1];
struct SE{
int ne,to;
}se[maxn<<1];
int h[maxn],num_edge=1;
inline void add_edge(int f,int to){
edge[++num_edge].ne=h[f];
edge[num_edge].to=to;
h[f]=num_edge;
}
int sh[maxn],num_se=1;
inline void add_se(int f,int to){
se[++num_se].ne=sh[f];
se[num_se].to=to;
sh[f]=num_se;
}
namespace Tree{//树的情况
int dep[maxn],fa[maxn],dfn[maxn],rnk[maxn],tot=0,top[maxn],son[maxn],size[maxn];
void dfs_1(int now){
int v;
size[now]=1;
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(dep[v]||v==fa[now])continue;
dep[v]=dep[now]+1;
fa[v]=now;
dfs_1(v);
size[now]+=size[v];
if(!son[now]||size[son[now]]<size[v])son[now]=v;
}
}
void dfs_2(int now,int t){
int v;
top[now]=t;
dfn[now]=++tot,rnk[tot]=now;
if(!son[now])return ;
dfs_2(son[now],t);
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(dfn[v]||v==fa[now]||v==son[now])continue;
dfs_2(v,v);
}
return ;
}
int L,R,t;
ll dta;
ll mi[maxn<<2];
inline void up(int now){mi[now]=min(mi[now<<1],mi[now<<1|1]);}
void build(int now,int l,int r){
if(l==r){
mi[now]=w[rnk[l]];//注意!!!
return ;
}
int mid=(l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
up(now);
return ;
}
void update(int now,int l,int r){
if(l==r){
mi[now]=dta;
return ;
}
int mid=(l+r)>>1;
if(t<=mid)update(now<<1,l,mid);
else update(now<<1|1,mid+1,r);
up(now);
return ;
}
ll ans=inf;
void query(int now,int l,int r){
if(L<=l&&r<=R){
ans=min(ans,mi[now]);
return ;
}
int mid=(l+r)>>1;
if(L<=mid)query(now<<1,l,mid);
if(mid<R)query(now<<1|1,mid+1,r);
up(now);
return ;
}
inline void query_path(int x,int y){
ans=inf;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])std::swap(x,y);
L=dfn[top[x]],R=dfn[x];
query(1,1,n);
x=fa[top[x]];
}
if(dfn[x]>dfn[y])std::swap(x,y);
L=dfn[x],R=dfn[y];
query(1,1,n);
return ;
}
void main(){
int x,y;
dep[1]=1,fa[1]=1;
dfs_1(1);
dfs_2(1,1);
build(1,1,n);
char opt[5];
//puts("fafa");
read(q);
while(q--){
scanf("%s",opt);
if(opt[0]=='C'){
read(x),read(dta);
t=dfn[x];
w[x]=dta;
update(1,1,n);
}
else{
read(x),read(y);
ans=inf;
if(x==y)puts("0");
else {
query_path(x,y);
printf("%lld\n",max(1ll*0,w[x]-ans));
//system("PAUSE");
}
}
}
return;
}
}
int inb[maxn],cnt=0;
multiset <ll> mib[maxn];
int dep[maxn],rnk[maxn],fa[maxn],dfn[maxn],tot=0,size[maxn],son[maxn],top[maxn];
void dfs_1(int now){
int v;size[now]=1;
for(ri i=sh[now];i;i=se[i].ne){
v=se[i].to;
if(v==fa[now]||dep[v])continue;
dep[v]=dep[now]+1,fa[v]=now;
dfs_1(v);
size[now]+=size[v];
if(!son[now]||size[son[now]]<size[v])son[now]=v;
}
return ;
}
bool vis[maxn];
void dfs_2(int now,int t){
int v;top[now]=t;
dfn[now]=++tot,rnk[tot]=now;
if(!son[now])return ;
dfs_2(son[now],t);
for(ri i=sh[now];i;i=se[i].ne){
v=se[i].to;
if(dfn[v]||v==son[now]||v==fa[now])continue;
dfs_2(v,v);
}
return ;
}
int L,R,t;
ll lst,dta;
ll mi[maxn<<2];
inline void up(int now){mi[now]=min(mi[now<<1],mi[now<<1|1]);}
void build(int now,int l,int r){
if(l==r){
mi[now]=*mib[rnk[l]].begin();
return ;
}
int mid=(l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
up(now);
}
void update(int now,int l,int r){
if(l==r){
mib[rnk[l]].erase(mib[rnk[l]].lower_bound(lst));
mib[rnk[l]].insert(dta);
mi[now]=*mib[rnk[l]].begin();
return ;
}
int mid=(l+r)>>1;
if(t<=mid)update(now<<1,l,mid);
else update(now<<1|1,mid+1,r);
up(now);
return ;
}
ll ans=inf;
void query(int now,int l,int r){
if(L<=l&&r<=R){
ans=min(ans,mi[now]);
return ;
}
int mid=(l+r)>>1;
if(L<=mid)query(now<<1,l,mid);
if(mid<R)query(now<<1|1,mid+1,r);
up(now);
return ;
}
inline void query_path(int x,int y){
ans=inf;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])std::swap(x,y);
L=dfn[top[x]],R=dfn[x];
//printf("%d %d %d %d\n",x,y,L,R);
query(1,1,cnt);
x=fa[top[x]];
}
if(dfn[x]>dfn[y])std::swap(x,y);
L=dfn[x],R=dfn[y];//puts("wtf");
//printf("%d %d %d %d\n",x,y,L,R);
query(1,1,cnt);
return ;
}
int low[maxn],dd[maxn],pc=0;
bool bri[maxn<<1];
void tarjan(int now,int id){
int v;
dd[now]=low[now]=++pc;
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(!dd[v]){
tarjan(v,i);
low[now]=min(low[now],low[v]);
if(dd[now]<low[v]){
bri[i]=bri[i^1]=1;
}
}
else if(i!=(id^1))low[now]=min(low[now],dd[v]);
}
return ;
}
void pre_dfs(int now,int fa){
int v;
vis[now]=1;
mib[cnt].insert(w[now]);
inb[now]=cnt;
//printf("%d %d\n",now,fa);
for(ri i =h[now];i;i=edge[i].ne){
v=edge[i].to;
if(inb[v]||bri[i]||bri[i^1]||v==fa)continue;
pre_dfs(v,now);
}
return ;
}
bool fg=0;
void pre_ck(int now,int fa){
int v;vis[now]=1;
for(ri i=h[now];i;i=edge[i].ne){
v=edge[i].to;
if(v==fa)continue;
if(vis[v]){fg=1;return ;}
pre_ck(v,now);
}
return ;
}
int main(){
int x,y;
FO(paoshang);
//freopen("paoshang1.in","r",stdin);
read(n),read(m);
for(ri i=1;i<=n;i++)read(w[i]);
for(ri i=1;i<=m;i++){
read(x),read(y);
add_edge(x,y);
add_edge(y,x);
}
pre_ck(1,0);
if(!fg){Tree::main();return 0;}
memset(vis,0,sizeof(vis));
for(ri i=1;i<=n;i++)if(!dd[i])tarjan(i,0);
for(ri i=1;i<=n;i++){
if(!inb[i]){
cnt++;
pre_dfs(i,0);
}
}
for(ri i=1;i<=n;i++){
x=inb[i];
for(ri j=h[i];j;j=edge[j].ne){
y=inb[edge[j].to];
if(x!=y){
add_se(x,y);
add_se(y,x);
}
}
}
//printf("--%d--\n",cnt);
dep[1]=1,fa[1]=0;
tot=0;
dfs_1(1);
dfs_2(1,1);
build(1,1,cnt);
read(q);
char opt[5];
while(q--){
scanf("%s",opt);
if(opt[0]=='C'){
read(x),read(dta);
lst=w[x];
t=dfn[inb[x]];
w[x]=dta;
update(1,1,cnt);
}
else{
read(x),read(y);
if(x==y)puts("0");
else {
query_path(inb[x],inb[y]);
printf("%lld\n",max(1ll*0,w[x]-ans));
}
}
}
return 0;
}