题目

\(n\)个节点的树,边权为正整数。

从1 号点开始走一个路径并最终回到 1 号点,且这条路径经过了所有的边。

一条路径的代价就是它经过的边的边权之和。

可以加若干条额外边,第 i 条加的额外边的边权为 正整数\(A_ i\) 。

注意,不一定要经过所有的额外边

对于所有的$ K \in [0, m]$,你需要输出允许加 \(\le K\) 条额外边的最小路径代价。

题解

  • 假设我们选了\(x\)条额外边,答案分为两部分:

    1.在前\(K\)条边里选\(x\)条边,使得长度和最小

    2.在原树上选\(x\)条边不相交的路径使得长度和最大

  • 考虑2,每次确定当前树的直径,将直径上的边全部取反,做\(x\)次即可

    具体用LCT维护ddp

    注意到ddp的话区间取反和翻转无法下放,但只有这两种操作

    可以预处理出splay节点取反,翻转的信息,修改的时候直接调用

  • 由于12都是凸的,所以我们直接三分求答案

  • 时间复杂度:\(O(n \ log ^2 n + n \ log \ n * LCT )\)  

Code

没写出来..先放YFZ的std:

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
typedef pair<ll,int> pii;
const ll inf=1e18;
int n,fa[maxn],K,C,W;
ll ans,sum,val[maxn],anses[maxn];
pii sval[maxn];
vector<pii>G[maxn]; struct pxx{
ll u,v,w;
pxx(){}
pxx(ll u,ll v,ll w):u(u),v(v),w(w){}
pxx operator+(const ll x)const{return pxx(u,v,w+x);}
pxx operator-(const ll x)const{return pxx(u,v,w-x);}
pxx operator+(const pxx& x)const{
pxx ret;
ret.u=u;ret.v=x.u;
if(ret.u<ret.v)swap(ret.u,ret.v);
ret.w=w+x.w;
return ret;
}
int operator<(const pxx& d)const{
if(w!=d.w)return w<d.w;
if(u!=d.u)return u<d.u;
return v<d.v;
}
};
//定义一条链的结构体
struct data{
pxx pre,suf,ans;ll sum;
data(){}
data(pxx pre,pxx suf,pxx ans,ll sum):pre(pre),suf(suf),ans(ans),sum(sum){}
data operator+(const data& d)const{
data ret;
ret.pre=max(pre,d.pre+sum);
ret.suf=max(suf+d.sum,d.suf);
ret.ans=max(ans,d.ans);
ret.ans=max(ret.ans,suf+d.pre);
ret.sum=sum+d.sum;
return ret;
}
};
//定义一个节点的信息,类似于最大子段和
namespace LCT{
int ch[maxn][2],fa[maxn],tg[maxn],ftg[maxn];
ll val[maxn];
multiset<pxx> st[maxn],stans[maxn];
data dp[maxn];
pxx cpre[maxn],cans[maxn];
data a[2][maxn],ra[2][maxn];
void clr(int n){
for(int i=1;i<=n;++i){
ch[i][0]=ch[i][1]=fa[i]=tg[i]=ftg[i]=val[i]=0;
st[i].clear(),stans[i].clear();
}
memset(dp,0,sizeof(data)*n);
memset(cpre,0,sizeof(pxx)*n);
memset(cans,0,sizeof(pxx)*n);
for(int i=0;i<2;++i){
memset(a[i],0,sizeof(data)*n);
memset(ra[i],0,sizeof(data)*n);
}
}
//
void upd(int o){
int ls=ch[o][0],rs=ch[o][1];
if(o>n){
a[0][o]=ra[0][o]=data(dp[o].pre+val[o],dp[o].pre+val[o],dp[o].ans,val[o]);
a[1][o]=ra[1][o]=data(dp[o].pre-val[o],dp[o].pre-val[o],dp[o].ans,-val[o]);
} else {
a[1][o]=ra[1][o]=
a[0][o]=ra[0][o]=data(dp[o].pre,dp[o].pre,max(dp[o].pre+pxx(o,0,0),dp[o].ans),0);
}
if(ls){
for(int i=0;i<2;++i){
a[i][o]=a[i][ls]+a[i][o];
ra[i][o]=ra[i][o]+ra[i][ls];
}
}
if(rs){
for(int i=0;i<2;++i){
a[i][o]=a[i][o]+a[i][rs];
ra[i][o]=ra[i][rs]+ra[i][o];
}
}
}
//
void _pd(int o,int t,int ft){
if(ft){
ftg[o]^=1;
swap(a[0][o],a[1][o]);
swap(ra[0][o],ra[1][o]);
val[o]=-val[o];
}
if(t){
tg[o]^=1;
swap(ch[o][0],ch[o][1]);
swap(a[0][o],ra[0][o]);
swap(a[1][o],ra[1][o]);
}
}
//修改
void pd(int o){
if(ch[o][0])_pd(ch[o][0],tg[o],ftg[o]);
if(ch[o][1])_pd(ch[o][1],tg[o],ftg[o]);
tg[o]=ftg[o]=0;
}//下放
bool isroot(int x){
if(!x||!fa[x])return true;
return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;
}
void rotate(int p){
int q=fa[p],y=fa[q],k=(ch[q][1]==p);
if(!isroot(q))ch[y][ch[y][1]==q]=p;
fa[ch[q][k]=ch[p][k^1]]=q;
fa[ch[p][k^1]=q]=p,fa[p]=y;
upd(q);
}
void splay(int x){
int y;
while(!isroot(x)){
pd(fa[y=fa[x]]),pd(y),pd(x);
if(!isroot(y)){
if((ch[fa[y]][1]==y)^(ch[y][1]==x))rotate(x);
else rotate(y);
}
rotate(x);
}
pd(x),upd(x);
}
//
void uupd(int x){
if(x<=n){
dp[x].pre=*st[x].rbegin();
dp[x].ans=*stans[x].rbegin();
if(st[x].size()>=2){
auto it=st[x].end();
dp[x].ans=max(dp[x].ans,*prev(it)+*prev(prev(it)));
}
} else {
dp[x].pre=st[x].size()?*st[x].rbegin():pxx(0,0,-inf);
dp[x].ans=stans[x].size()?*stans[x].rbegin():pxx(0,0,-inf);
if(st[x].size()>=2){
auto it=st[x].end();
dp[x].ans=max(dp[x].ans,*prev(it)+*prev(prev(it))+val[x]);
}
}
}
//修改一个点的轻链信息
void cadd(int x,int y){
// printf("cadd:(%d)<%lld,%lld,%lld>\n",y,a[0][y].ans.u,a[0][y].ans.v,a[0][y].ans.w);
st[x].insert(a[0][y].pre);
stans[x].insert(a[0][y].ans);
uupd(x);
}
//加入一个轻链信息
void del(int x,int y){
// printf("del:(%d)[%lld,%lld,%lld]\n",y,a[0][y].ans.u,a[0][y].ans.v,a[0][y].ans.w);
st[x].erase(a[0][y].pre);
stans[x].erase(a[0][y].ans);
uupd(x);
}
//删除一个轻链信息
void access(int x){
for(int y=0;x;y=x,x=fa[x]){
splay(x);
// printf("{%d,%d}",x,y);
if(ch[x][1])cadd(x,ch[x][1]);
if(y)del(x,y);
ch[x][1]=y;
upd(x);
}
} void rever(int x){
access(x),splay(x);
_pd(x,1,0),pd(x);
} void link(int u,int v){
access(u),splay(u);
rever(v);
fa[v]=u;
cadd(u,v);
upd(u);
}
void mdy(int u,int v){
rever(u),access(v),splay(v);
_pd(v,0,1),pd(v);
}
void dfs(int u){
pd(u);
if(ch[u][0])dfs(ch[u][0]);
printf("[%d[%d,%d](%lld,%lld,%lld,%d)]",u,ch[u][0],ch[u][1],dp[u].pre.w,a[0][u].ans.w,a[1][u].ans.w,a[1][u].sum);
if(ch[u][1])dfs(ch[u][1]);
}
};
int ptr=0;
void dfs(int u,int f){
for(auto v:G[u])if(v.first!=f){
dfs(v.first,u);
LCT::fa[v.first]=v.second;
LCT::cadd(v.second,v.first);
LCT::fa[v.second]=u;
LCT::upd(v.second);
LCT::cadd(u,v.second);
LCT::upd(u);
}
LCT::upd(u);
}
//?
ll trsum[maxn],trcnt[maxn];
ll calzzz(ll x){
ll nw=0,ans=0,nwcnt=0;
for(int i=21;i>=0;--i){
nw+=(1<<i);
if(nw>K||trcnt[nw]+nwcnt>x)nw-=(1<<i);
else nwcnt+=trcnt[nw],ans+=trsum[nw];
}
return ans+anses[x];
}
//BIT维护1
ll solans(ll K){
int l=0,r=K-1;
ll ans=calzzz(K);
while(l<=r){
int mid=l+r>>1;
if(calzzz(mid)>calzzz(mid+1))l=mid+1,ans=min(ans,calzzz(mid+1));
else r=mid-1,ans=min(ans,calzzz(mid));
}
return ans;
}
//二分斜率求答案
int main(){
freopen("love.in","r",stdin);
freopen("love.out","w",stdout);
scanf("%d%d",&n,&K);
sum=0;
ptr=n;
LCT::clr(2*n);
for(int i=1;i<=n;++i)G[i].clear();
for(int i=1;i<=n;++i){
LCT::st[i].insert(pxx(i,0,0));
LCT::stans[i].insert(pxx(i,i,0));
LCT::uupd(i),LCT::upd(i);
}
for(int i=2,u,v,w;i<=n;++i){
scanf("%d%d%d",&u,&v,&w);
++ptr;
LCT::val[ptr]=w;
LCT::uupd(ptr),LCT::upd(ptr); G[u].push_back(pii(v,ptr));
G[v].push_back(pii(u,ptr));
sum+=2*w;
}
dfs(1,0);
for(int i=1;i<=K;++i)scanf("%lld",&val[i]),sval[i]=pii(val[i],i);
sort(sval+1,sval+K+1);
int flg=0;
anses[0]=sum;
printf("%lld ",solans(0));
for(int i=1;i<=K;++i){
int R=1;
LCT::rever(R);
pxx path=LCT::a[0][R].ans;
sum-=path.w;
anses[i]=sum;
if(path.w==0&&!flg){
flg=1;
fprintf(stderr,"[%d]",i);
}
for(int x=lower_bound(sval+1,sval+K+1,pii(val[i],i))-sval;x<=K;x+=x&-x)
trsum[x]+=val[i],trcnt[x]++;
int u=path.u,v=path.v;
LCT::mdy(u,v);
printf("%lld ",solans(i));
}
}

【JZOJ6232】【20190625】喜欢最最痛的更多相关文章

  1. 5.29 SD省队培训D1

    5.29 SD省队培训D1 自闭的一天 T1 梦批糼 先咕一咕(两天之内一定补上) T2 等你哈苏德 继续咕(一星期之内补上) T3喜欢最最痛 四十分做法: 首先,我们发现同一个点加两条额外边是一件非 ...

  2. 更喜欢从一而终?bing测试在新窗口打开链接遭美国网友痛批

                  原链接地址:http://www.cnbeta.com/articles/186529.htm 我们都知道在中国网站点击一个链接之后,默认在新窗口或新标签打开,大家也很熟悉 ...

  3. [置顶] IT老男人读《因为痛,所以叫青春》

    最近偶然,从别人的书桌上看到这本书,其中有个关于时间的解释,很是让为成功焦虑的老男人受用.   因此,我喜欢将人生的80年跟一天中的24小时进行对照. 人生时钟的计算方法十分简单.24小时相当于144 ...

  4. Eclipse/MyEclipse 最最常用的快捷键

    F 键类 F2 显示详细信息 F3 跳到声明或定义的地方 Ctrl + 键类 Ctrl+1 快速修复 ( 最经典的快捷键 , 就不用多说了 ) Ctrl+D 删除当前行 Ctrl+E 快速显示当前 E ...

  5. Swagger解决你手写API接口文档的痛

    首先,老规矩,我们在接触新事物的时候, 要对之前学习和了解过的东西做一个总结. 01 痛     苦 不做.不行 之前,前后端分离的系统由前端和后端不同的编写,我们苦逼的后端工程师会把自己已经写完的A ...

  6. 早日选择一门自己喜欢的,然后瞄准目标,不达目的誓不罢休。像文章的作者一样成为一名成功的IT人士。

    hawk的奋斗历程. 来自:LinuxForum  :http://www3.linuxforum.net/ 原址:http://www.linuxforum.net/forum/gshowflat. ...

  7. Linq表达式、Lambda表达式你更喜欢哪个?

    什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在& ...

  8. PHPStorm配置自己喜欢的主题

    PHPstorm默认的主题和可选的主题有时候不能满足有些人的需求,怎么配置自己喜欢的主题呢? 1.首先先去下载自己喜欢的主题:http://www.phpstorm-themes.com/ 但是在下载 ...

  9. 移动信息化不能延续PC时代的痛

    当下,随着移动时代的到来,手机功能逐步完善,各个行业针对这一现象纷纷制定了相应的营销计划,于是霎时间兴起了一股网上订票/网上订饭/网上预约的热潮. 而对于IT行业,成为企业信息化最火的代名词莫过于移动 ...

随机推荐

  1. SQL Server的外键必须引用的是主键或者唯一键(转载)

    问: In SQL Server , I got this error -> "There are no primary or candidate keys in the refere ...

  2. SQLServer作业调用链接服务器失败解决办法

    新建一个SQL作业,语句手动执行OK,但是作业计划执行总是报错. 消息已以用户 NT SERVICE\SQLSERVERAGENT 的身份执行. 链接服务器 "172.16.10.23&qu ...

  3. 关于BASE 24 ,BASE 64原理以及实现程序

    关于BASE 24 ,BASE 64原理以及实现程序 来源 https://wangye.org/blog/archives/5/ 可能很多人听说过Base64编码,很少有人听说过Base24编码,B ...

  4. Java IO---缓冲流和转换流

    一. 缓冲流 ​ 缓冲流是处理流的一种,也叫高效流,是对4个基本输入输出流的增强,它让输入输出流具有1个缓冲区,能显著减小与外部的IO次数,从而提高读写的效率,并且提供了一些额外的读写方法. ​ 因为 ...

  5. Java自学-日期 日期格式化

    Java中使用SimpleDateFormat 进行日期格式化类 SimpleDateFormat 日期格式化类 示例 1 : 日期转字符串 y 代表年 M 代表月 d 代表日 H 代表24进制的小时 ...

  6. IntelliJ IDEA重命名变量的问题

    当我尝试使用Shift+ F6或简单地使用Refactor => Rename重命名变量时,有时intellij不仅重命名我想要的那个,而且还重命名具有相同名称的所有其他变量(在其他文件中)以及 ...

  7. vue 封装公用函数

    Vue 函数封装 格式化浏览器时间 /** * 格式化时间 * @param params * @param blo 默认为true * @returns {string} * @constructo ...

  8. Spring Data JPA的低级错误

    //课程表 @Entity public class Class { @GeneratedValue(strategy = GenerationType.AUTO) @Id private Long ...

  9. Nginx学习(二)

    ------------恢复内容开始------------ Nginx配置文件 主配置文件结构:四部分 main block:主配置段,既全局配置段,对Http,mail都有效 event{ }事件 ...

  10. svn进行上传项目

    当svn的服务器搭建成功后,就可以进行上传项目了. 右键,选择客户端的repo-browser, 输入地址 然后就可以浏览所有项目: 然后在版本仓库上,右键,add folder, 添加对应的文件夹即 ...