题目

\(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. 安装软件时出现这样错误:文件“proe50-1a.bin”无法在“C:\User\ZFTL\Desktop\proe50”定位,请插入正确的磁盘或选择其他文件夹

    把里面的文件改成proe50-1a.bin就可以了.

  2. c#NAudio 录音功能实现

    在网上找了很多类似录音教程效果都不好,或根本不能录音,代码由网上借鉴修改(完整实现录音播放功能) 1.首先新建引用类  RecordController public class RecordCont ...

  3. php调用webservice接口,java代码接收不到参数

    前段时间做了一个项目的二次开发,有个功能是需要php调用java实现的webservice接口,并传递一些参数给接口,然后按照对方提供的接口说明文档进行传参调用,java那边有接收到请求,但是参数总是 ...

  4. 【转载】C#中使用Insert方法往ArrayList集合指定索引位置插入新数据

    ArrayList集合是C#中的一个非泛型的集合类,是弱数据类型的集合类,可以使用ArrayList集合变量来存储集合元素信息,在ArrayList集合操作过程中,可以使用ArrayList集合类的I ...

  5. 商业BISYNES英语BISYNES商务

    business from English bisynes Etymology From Middle English bisynes Hyphenation: business Noun busin ...

  6. 通过nginx部署前端代码实现前后端分离

    实现前后端分离,可以让前后端独立开发.独立部署.独立单测,双方通过JSON进行数据交互. 对于前端开发人员来说,不用每次调试都需要启动或配置Java/Tomcat运行环境:对于后端开发人员来说 ,也不 ...

  7. Python 的稀疏矩阵

    什么是稀疏矩阵 简单的说,如果一个矩阵中大部分元素为0,就被称为稀疏矩阵. 对于稀疏矩阵而言,实际存储的数据项很少.如果在计算机中采用传统的二维数组(Python中用二维列表)来存储稀疏矩阵,就会浪费 ...

  8. Python 操作 MySQL 数据库

    使用示例: import pymysql #python3 conn=pymysql.connect(host="localhost",port=3306,user="r ...

  9. 12306 抢票项目霸榜 GitHub,标星即将破万

    十一将至,你买到回家的火车票了吗?如果没有,你可以试着打开 GitHub,在搜索栏键入 12306 的关键词,我相信你会发现一个新大陆.没错,这里有 1572 个抢票项目.它们大多用 Python.J ...

  10. JavaScript数值和字符串、特殊字符

    一.JavaScript数值 1.整数和浮点数 根据国际标准 IEEE 754,64 位浮点数格式的 64 个二进制位中,第0 位到第 51 位储存有效数字部分,第 52 到第 62 位储存指数部分, ...