再努力一次
再努力一次吧。
牛客多校第一场F.cut
对于区间“合并”,段数变化是O(n)的
在一段里面,数字都是递增或递减的
只需要维护一颗权值线段树,以及递增递减标志就可以表示完整个区间
把一段分成两段,或者把两段合成一段,本质就是线段树的合并或者分裂,都可以实现
每次询问,先把l,r分裂出来,然后中间不断合并即可
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=5000005;
set<int> ss;
struct node
{
int l,r,len,ans;
node (int _l,int _r,int _len,int _ans):l(_l),r(_r),len(_len),ans(_ans){}
node()
{
l=r=ans=len=0;
}
node friend operator +(node a,node b)
{
if (!b.len) return a;
if (!a.len) return b;
return node(a.l,b.r,a.len+b.len,a.ans+b.ans+((a.r&1)^(b.l&1)));
}
void print ()
{
printf("%d %d %d %d\n",l,r,len,ans);
}
}tr[N*2],seg[N/10];int num;
bool rev[N];
vector<int> Del;
int s1[N],s2[N];
int rt[N];
int n,m;
int new_node ()
{
int x;
if (!Del.empty()) {x=Del.back();Del.pop_back();}
else x=++num;
return x;
}
void del (int x) {Del.push_back(x);s1[x]=s2[x]=0;tr[x].len=tr[x].ans=0;}
void bt (int &now,int L,int R,int x)
{
now=new_node();
if (L==R)
{
tr[now]=node(x,x,1,0);
return ;
}
int mid=(L+R)>>1;
if (x<=mid) bt(s1[now],L,mid,x);
else bt(s2[now],mid+1,R,x);
tr[now]=tr[s1[now]]+tr[s2[now]];
}
int Merge (int rt1,int rt2)
{
if (rt1==0||rt2==0) return rt1|rt2;
// printf("%d %d\n",rt1,rt2);
s1[rt1]=Merge(s1[rt1],s1[rt2]);
s2[rt1]=Merge(s2[rt1],s2[rt2]);
tr[rt1]=tr[s1[rt1]]+tr[s2[rt1]];
del(rt2);
return rt1;
}
void modify (int now,int l,int r,int x)
{
if (l==r)
{
seg[now]=tr[rt[x]];
if (rev[x]) swap(seg[now].l,seg[now].r);
return ;
}
int mid=(l+r)>>1;
if (x<=mid) modify(now<<1,l,mid,x);
else modify(now<<1|1,mid+1,r,x);
seg[now]=seg[now<<1]+seg[now<<1|1];
}
node query (int now,int L,int R,int l,int r)
{
if (L==l&&R==r) return seg[now];
int mid=(L+R)>>1;
if (r<=mid) return query(now<<1,L,mid,l,r);
else if (l>mid) return query(now<<1|1,mid+1,R,l,r);
else return query(now<<1,L,mid,l,mid)+query(now<<1|1,mid+1,R,mid+1,r);
}
void split (int rt1,int &rt2,int k,int Rev)
{
if (tr[rt1].len==k) return ;
rt2=new_node();
if (Rev==0)
{
if (k>tr[s1[rt1]].len) split(s2[rt1],s2[rt2],k-tr[s1[rt1]].len,Rev);
else
{
swap(s2[rt1],s2[rt2]);
split(s1[rt1],s1[rt2],k,Rev);
}
}
else
{
if (k>tr[s2[rt1]].len) split(s1[rt1],s1[rt2],k-tr[s2[rt1]].len,Rev);
else
{
swap(s1[rt1],s1[rt2]);
split(s2[rt1],s2[rt2],k,Rev);
}
}
tr[rt1]=tr[s1[rt1]]+tr[s2[rt1]];
tr[rt2]=tr[s1[rt2]]+tr[s2[rt2]];
}
set<int> :: iterator SP(int x)
{
auto now=ss.lower_bound(x);
if (*now==x) return now;
now--;
split(rt[*now],rt[x],x-*now,rev[x]=rev[*now]);
modify(1,1,n,*now);
modify(1,1,n,x);
return ss.insert(x).first;
}
int main()
{
scanf("%d%d",&n,&m);
ss.insert(n+1);
for (int u=1;u<=n;u++)
{
int x;
scanf("%d",&x);
bt(rt[u],1,n,x);
modify(1,1,n,u);
ss.insert(u);
}
while (m--)
{
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
auto L=SP(l),R=SP(r+1);
if (op<=2)
{
L++;
for (auto i=L;i!=R;i++)
{
// tr[rt[*i]].print();
// tr[rt[l]].print();
rt[l]=Merge(rt[l],rt[*i]);
modify(1,1,n,*i);
//printf("Merge:%d %d\n",l,*i);
}
// tr[rt[l]].print();
rev[l]=op-1;
modify(1,1,n,l);
ss.erase(L,R);
}
else
{
printf("%d\n",query(1,1,n,l,r).ans+1);
}
}
return 0;
}
codeforces 1726F. Late For Work
可以发现,花在路上的时间,不管等不等灯都一定要花的
因此,我们可以前把每个路口当前的时间加上路程时间,然后变成路上都不需要花时间
然后每一个灯,能通过的时间,显然有
同时这也就是说我们每一个灯会拦住一段时间,前面来的人都会在这里被拦住
我们设表示在第i个路口等了灯往后还要多久
这个显然是会走到下一个灯的地方,然后一直到那个灯的L才能走
相当于我们每一次要插入一段时间,表示这段时间都要等某一个灯
然后支持往后询问我要等哪一个灯
set对区间进行维护即可
codeforces 1065F
题意是任意一个叶子,所以可以用某一个浅的叶子刷
考虑dp,表示从子树最后可以回到根,表示不需要回到根
只可以从转移过来,并且需要满足该子树里面有一个可以到达父亲的节点来刷
则可以再的基础上再选择一个,表示最后停在这个子树里面
codeforces 730I
I. Olympiad in Programming and Sports
n只有3000,是一个可以暴力跑费用流的范围。
但可以通过模拟费用流优化
每一条增广路只有以下四种情况:
1.选择一个A
2.选择一个B
3.选择一个A,并将一个A换为B
4.选择一个B,并将一个B换为A
用四个堆分别维护这四个操作即可
gym102538 E
easywin
之前在随缘更新题解里面写过一次。
但当时偷懒没有写代码。
照着当时写的思路把坑补上了。
亲测写得还是很清晰的
codeforce865D
cf865D
我们可以让某一天可以同时买或同时卖,这样相互抵消就可以了
因此可以先假设每一天都买
然后考虑是否要卖出,如果卖出了,那么一定是选择之前最便宜的一个
值得注意的是,如果我们再某一天选择了卖出,并借此换掉了之前的一支股票。那么我们再这一天其实是可以买两次的,可以理解为反悔当天买入的操作。
种树
种树
题目大意:有n个数,要你在里面不超过选择k个,要求不能有选择的数相邻。问你最大价值是多少。
题解:
经典老番了。
先介绍一个经典的贪心思路:
如果我们选择了i,那么i-1和i+1要么同时选,要么同时不选。因为如果只选了一个显然不如选会i优。
因此便有了贪心的思路,选完i后,把i,i+1,i-1合并成a[i+1]+a[i-1]-a[i]。然后重复子问题即可。
再介绍一个费用流的思路:
两排点,第一排为奇数的间隔,第二排为偶数的间隔。两排点之间以具体的数来连边。然后跑流量为k的费用流即可。
考虑模拟费用流,可以发现,每一次我们一定会选择一段 (不选,选,不选,选,不选),然后集体大反转
可以得到和上面贪心一模一样的做法。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通