题目

\(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. C# Modbus 数据读取 使用NModBus4库

    ModBus通讯协议 方法名 作用 所需参数 返回值 对应功能码 ReadCoils 读取DO的状态 从站地址(8位) byte slaveAddress 起始地址(16位) ushort start ...

  2. 一个简单便捷的树形显示Ztree

    这是本人在闲时研究的一个用于显示树形列表的小玩意. zTree 是一个依靠 jQuery 实现的多功能 “树插件”.优异的性能.灵活的配置.多种功能的组合是 zTree 最大优点. 下面就说说怎么用吧 ...

  3. JXL 简单示例

    JXL 1 Overview 1 Overview Home page: http://jexcelapi.sourceforge.net/ JXL 是一个开源的 Excel 开发库,支持 Excel ...

  4. JavaSE02:第一个程序

    HelloWorld! 写第一个程序步骤 建一个文件,文件名改为HelloWorld.java 用文本编辑器打开并编写代码 public class HelloWorld{ public static ...

  5. 浏览器标签页切换时jquery动画的问题

    最近公司在做大屏设备上的页面,其中动画的部分居多,开始的时候是用的jquery做的动画,在做完后无意中发现jquery动画存在一个问题,就是浏览器在切换标签页后,过段时间切换回来页面中的动画会出现连续 ...

  6. 转摘jemeter学习-连接数据库之jdbc请求

    JMETER连接数据库 mysql下载地址:https://dev.mysql.com/downloads/connector/j/ mysql连接器根据语言选择/J,用的是Mac,选择下载.tar. ...

  7. JAVA Coder 的《深入分析Java Web 技术内幕》读书笔记

    本文基于<深入分析Java Web 技术内幕> <深入分析Java Web 技术内幕>,作者是 许令波,电子工业出版社.本文只是记录书本当中的精彩部分,作个人回顾和技术分享,请 ...

  8. Oracle数据库主外键 级联删除记录

    /** * 1. NO ACTION :指当删除主表中被引用列的数据时,如果子表的引用列中包含该值,则禁止该操作执行. * * 2. SET NULL :指当删除主表中被引用列的数据时,将子表中相应引 ...

  9. windows10安装redis

    下载 github上下载最新(或者你需要的版本)的redis安装包,下载地址如下: https://github.com/microsoftarchive/redis/releases 打开点击版本号 ...

  10. windows定时器编程

    目前,Windows下的定时器编程主要有三种方式. 1)SetTimer定时器是利用Windows窗口消息WM_TIMER来实现的.使用方法非常简单,SetTimer创建定时器,KillTimer销毁 ...