2024.6.1 联系记录
1. 消耗战(P2495)
题目描述
在一场战争中,战场由
侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到
输入格式
第一行一个整数
接下来
第
接下来
输出格式
输出共
数据规模与约定
- 对于
的数据, 。 - 对于
的数据, 。 - 对于
的数据, 。 - 对于
的数据, 。
简化一下就是每次询问给一堆关键点,每次可以删一些边,删边有代价,求所有关键点与根不连通的最小代价。
暴力 DP 显然,但
考虑典中典虚树,虚树建完之后咋搞呢,发现如果把一个关键点和根隔开的最小代价就是直接删到根路径中最小的边,dfs 预处理一下就和暴力 dp 没区别了。
要记住虚树咋求的,单调栈维护一条链,如果赛时写挂了就根号分治骗分。
#include<bits/stdc++.h>
namespace Limie{
#define x first
#define y second
#define int long long
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
}using namespace Limie;
int n,m;
int h[500010],e[1000010],w[1000010],ne[1000010],idx;
int a[500010],dfn[500010],cnt;
int f[500010][20],d[500010],mn[500010];
int stk[500010],top,k;
bool st[500010];
void add(int a,int b,int c){e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;}
void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;}
void dfs(int u,int fa)
{
dfn[u]=++cnt;
f[u][0]=fa;
d[u]=d[fa]+1;
for(int i=1;i<20;i++)f[u][i]=f[f[u][i-1]][i-1];
for(int i=h[u];~i;i=ne[i]){
int v=e[i];
if(v!=fa){
if(u!=1)mn[v]=min(mn[u],w[i]);
else mn[v]=w[i];
dfs(v,u);
}
}
}
int lca(int x,int y)
{
if(d[x]<d[y])x^=y^=x^=y;
for(int i=19;i>=0;i--)
if((1<<i)<=d[x]-d[y])x=f[x][i];
if(x==y)return x;
for(int i=19;i>=0;i--)
if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
bool cmp(int x,int y){return dfn[x]<dfn[y];}
void build()
{
sort(a+1,a+k+1,cmp);
stk[top=1]=1,h[1]=-1;
for(int i=1;i<=k;i++){
if(a[i]!=1){
int l=lca(a[i],stk[top]);
if(l!=stk[top]){
while(dfn[l]<dfn[stk[top-1]])add(stk[top-1],stk[top]),top--;
if(dfn[l]!=dfn[stk[top-1]]) {
h[l]=-1;
add(l,stk[top]),stk[top]=l;
}else add(l,stk[top--]);
}
h[a[i]]=-1;
stk[++top]=a[i];
}
}
for(int i=1;i<top;i++)add(stk[i],stk[i+1]);
}
int dp(int u)
{
int ans=0;
for(int i=h[u];~i;i=ne[i]){
int v=e[i];
ans+=dp(v);
}if(u==1)return ans;
if(st[u])return mn[u];
else return min(ans,mn[u]);
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int i;
cin>>n;
memset(h,-1,sizeof h);
for(i=1;i<n;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c),add(b,a,c);
}
dfs(1,1);
memset(h,-1,sizeof h);
cin>>m;
while(m--){
cin>>k;
idx=0;
for(i=1;i<=k;i++){
cin>>a[i];
st[a[i]]=1;
}
build();
cout<<dp(1)<<'\n';
for(i=1;i<=k;i++)st[a[i]]=0;
}
}
2.最大 m 子段和(加强版)/CF280D (加强加强版)
先考虑 CF280D。
题面
长度为
1.修改某个位置的值
2.询问区间
一共有
如果
发现不会
思考贪心算法,发现可以反悔,就是每次贪心取最大子段和喵,取完后把区间取反,如果取到了两个区间有交,那么重合部分相加为
随便写写就过了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int n,m;
#define mid (l+r>>1)
struct Extm{
int l,r,ans;
Extm operator+(const Extm &w)const{return {l,w.r,w.ans+ans};}
bool operator<(const Extm &y)const{return ans<y.ans;}
bool operator>(const Extm &y)const{return ans>y.ans;}
};
struct Node{
int l,r;
Extm sum;
Extm premax,sufmax,ansmax;
Extm premin,sufmin,ansmin;
bool tag;
}tr[400010];
Node operator+(const Node &x,const Node &y)
{
Node u;
u.sum=x.sum+y.sum;
u.premax=max(x.premax,x.sum+y.premax);
u.sufmax=max(y.sufmax,x.sufmax+y.sum);
u.ansmax=max({x.ansmax,y.ansmax,x.sufmax+y.premax});
u.premin=min(x.premin,x.sum+y.premin);
u.sufmin=min(y.sufmin,x.sufmin+y.sum);
u.ansmin=min({x.ansmin,y.ansmin,x.sufmin+y.premin});
u.tag=0;
return u;
}
void pushtag(int u)
{
swap(tr[u].premin,tr[u].premax);
swap(tr[u].sufmin,tr[u].sufmax);
swap(tr[u].ansmin,tr[u].ansmax);
tr[u].premin.ans*=-1,tr[u].premax.ans*=-1;
tr[u].sufmin.ans*=-1,tr[u].sufmax.ans*=-1;
tr[u].ansmin.ans*=-1,tr[u].ansmax.ans*=-1;
tr[u].sum.ans*=-1;
tr[u].tag^=1;
}
void pushdown(int u)
{
if(!tr[u].tag)return;
pushtag(u<<1),pushtag(u<<1|1);
tr[u].tag=0;
}
void newnode(int u,int x,int c)
{
tr[u].premin=tr[u].premax={x,x,c};
tr[u].sufmin=tr[u].sufmax={x,x,c};
tr[u].ansmin=tr[u].ansmax={x,x,c};
tr[u].sum={x,x,c},tr[u].tag=0;
}
void modify(int u,int l,int r,int x,int c)
{
if(l==r)return newnode(u,x,c);
pushdown(u);
if(x<=mid)modify(u<<1,l,mid,x,c);else modify(u<<1|1,mid+1,r,x,c);
tr[u]=tr[u<<1]+tr[u<<1|1];
}
void reverse(int u,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return pushtag(u);
pushdown(u);
if(L<=mid)reverse(u<<1,l,mid,L,R);
if(mid<R)reverse(u<<1|1,mid+1,r,L,R);
tr[u]=tr[u<<1]+tr[u<<1|1];
}
Node query(int u,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return tr[u];
pushdown(u);
if(R<=mid)return query(u<<1,l,mid,L,R);
if(mid<L)return query(u<<1|1,mid+1,r,L,R);
return query(u<<1,l,mid,L,R)+query(u<<1|1,mid+1,r,L,R);
}
#undef mid
queue<Node> q;
int main()
{
int i;
cin>>n;
for(i=1;i<=n;i++){
int x;
cin>>x;
modify(1,1,n,i,x);
}
cin>>m;
while(m--){
int ty,l,r,k;
cin>>ty>>l>>r;
if(ty){
cin>>k;
int s=0;
while(k--){
Node ans=query(1,1,n,l,r);
if(ans.ansmax.ans<=0)break;
q.push(ans),s+=ans.ansmax.ans;
reverse(1,1,n,ans.ansmax.l,ans.ansmax.r);
}
cout<<s<<'\n';
while(q.size()){
Node ans=q.front();
reverse(1,1,n,ans.ansmax.l,ans.ansmax.r);
q.pop();
}
}else modify(1,1,n,l,r);
}
}
弱化版很简单喵,题意就是没有修改且区间为整个序列。
有神秘简单做法,挖个坑,回头补喵。
贴一份来自 wmh 的神仙代码。
#include<bits/stdc++.h>
using namespace std;
int a[1000005],zt[1000005];
long long b[1000005];
int nxt[1000005],pre[1000005],vist[1000005];
priority_queue<pair<long long,int>>pq;
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%d",&a[i]),zt[i]=(a[i]>=0);
long long ans=0;
int t=0;
for(int i=1;i<=n;){
int j=i;long long h=0;
while(j<=n&&zt[j]==zt[i])h+=a[j++];
if(zt[i])ans+=h;
if(zt[i]||(i>1&&j<=n))b[++t]=(h<0?h:-h);
i=j;
}
int k=max(0,(t+1)/2-m);
for(int i=1;i<=t;i++)pq.push(make_pair(b[i],i));
b[0]=b[t+1]=-1e18;
for(int i=1;i<t;i++)nxt[i]=i+1;
for(int i=2;i<=t;i++)pre[i]=i-1;
while(k--){
int aa=pq.top().second;
if(vist[aa]){
pq.pop();
k++;
continue;
}
ans+=pq.top().first;
pq.pop();
int a1=pre[aa],a2=nxt[aa];
nxt[pre[a1]]=pre[nxt[a2]]=aa;
pre[aa]=pre[a1],nxt[aa]=nxt[a2];
vist[a1]=vist[a2]=1;
pq.push(make_pair(b[aa]=b[a1]+b[a2]-b[aa],aa));
}
printf("%lld\n",ans);
return 0;
}
3. 和谐矩阵(P3164)
题目描述
我们称一个由
输入格式
输入一行,包含两个空格分隔的整数
输出格式
输出包含
一眼高消,跟昨天做的外星千足虫没有区别喵。
#include<bits/stdc++.h>
namespace Limie{
#define x first
#define y second
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
}using namespace Limie;
int n,m;
int dx[]={-1,0,1,0},dy[]={0,-1,0,1};
bitset<1610> a[1610];
void gauss()
{
for(int i=0;i<n*m;i++){
for(int j=i+1;j<n*m;j++)
if(a[j][i]){swap(a[i],a[j]);break;}
if(!a[i][i])a[i][i]=a[i][n*m]=1;
for(int j=0;j<n*m;j++)
if(j!=i&&a[j][i])a[j]^=a[i];
}
for(int i=0;i<n*m;i++){
if(i&&i%n==0)cout<<'\n';
cout<<a[i][n*m]<<' ';
}
}
int main()
{
int i,j;
cin>>n>>m;
for(i=0;i<n;i++)
for(j=0;j<m;j++){
a[i*m+j][i*m+j]=1;
for(int k=0;k<4;k++){
int x=i+dx[k],y=j+dy[k];
if(x<0||x>=n||y<0||y>=m)continue;
a[i*m+j][x*m+y]=1;
}
}
gauss();
}
4. ABC356
今晚有点原神。
D 使用 1<<x
结果 x=-1
,所以卡了一会喵。
F 是 fhq-treap 板子,调调细节就可以了喵。
G 不会喵。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】