D
题意
每次把最小的两个给合起来,然后把右边的一个变成这个数的两倍,问最后的序列
分析
我的做法有点蠢,直接暴力合并,开一个权值线段树,叶子结点开个set存位置,然后维护同种元素最多出现多少个,一边找一边并就好
最后把所有的叶子结点给扫一遍,map一下
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll inf = 1e18;
const ll N = 1234567;
inline ll read()
{
ll p=0; ll f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
ll rt,tot,lc[N<<2],rc[N<<2]; set<ll> s[N<<2]; ll c[N<<2];
void link(ll &u,ll L,ll R,ll k,ll cc)
{
if(!u) u=++tot;
if(L==R)
{
s[u].insert(cc);
c[u] = s[u].size();
return ;
}
ll mid = (L+R)>>1;
if(k<=mid) link(lc[u],L,mid,k,cc);
else link(rc[u],mid+1,R,k,cc);
c[u] = max(c[lc[u]] , c[rc[u]]);
}
void find(ll u,ll L,ll R)
{
if(L==R)
{
s[u].erase(s[u].begin());
link(rt,1,inf,2*L,*s[u].begin());
s[u].erase(s[u].begin());
c[u] = s[u].size();
//printf("%d\n",L);
return ;
}
ll mid=(L+R)>>1;
if(c[lc[u]] >= 2) find(lc[u],L,mid);
else find(rc[u],mid+1,R);
c[u] = max(c[lc[u]] , c[rc[u]]);
}
map<ll,ll> mp;
void qry(ll u,ll L,ll R)
{
if(!u) return ;
if(L==R)
{
for(auto i : s[u]) mp[i]=L;
return ;
}
ll mid=(L+R)>>1;
qry(lc[u],L,mid);
qry(rc[u],mid+1,R);
}
ll ans[N];
int main()
{
ll n = read(); rt=tot=0;
for(ll i=1;i<=n;i++)
{
ll x=read();
link(rt,1,inf,x,i);
}
while(1)
{
if(c[1] <= 1) break;
find(rt,1,inf);
}
qry(rt,1,inf);
printf("%d\n",mp.size());
for(auto i:mp) printf("%lld ",i.second);
return 0;
}
E
题意
在坐标轴上有很多个点,R,B,P,然后你要把这些点给连边,代价为坐标的绝对值的差, 然后使得这个图去掉R点后B和P都仍然全部联通或者去掉B点后R和P仍然全部都联通
分析
考虑P点之间的情况,要不就是P点之间连两条链,要不就是首先两个P点先连,然后对于R的点连向P点的情况就是分成两边,一边连前面的端点,一边连后面的端点,对于B也这样贪心,肯定有两个决策点,看看是连两条链优还是断开优
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll N = 1000010;
inline ll read()
{
ll p=0; ll f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
ll col[N],a[N]; ll n; ll p[N],plen = 0;
int main()
{
n=read();
for(ll i=1;i<=n;i++)
{
ll x = read(); char ch; scanf("\n%c",&ch);
if(ch=='R') col[i] = 1; else if(ch=='B') col[i] = 2; else col[i] = 3;
a[i] = x;
}
ll s=0,d=n+1;
for(ll i=1;i<=n;i++) if(col[i] == 3){s=i; break;}
for(ll i=n;i>=1;i--) if(col[i] == 3){d=i; break;}
if(s==0)
{
ll lst = 0; ll ans = 0;
for(ll i=1;i<=n;i++)
{
if(col[i] == 2) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}
lst = 0;
for(ll i=1;i<=n;i++)
{
if(col[i] == 1) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}printf("%lld\n",ans);
return 0;
}
ll lst = 0; ll ans = 0;
for(ll i=1;i<=s;i++)
{
if(col[i] == 2) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}
lst = 0;
for(ll i=1;i<=s;i++)
{
if(col[i] == 1) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}
lst = d;
for(ll i=d+1;i<=n;i++)
{
if(col[i] == 2) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}
lst = d;
for(ll i=d+1;i<=n;i++)
{
if(col[i] == 1) continue;
if(lst) ans+=a[i] - a[lst];
lst = i;
}
ll nx = 0;
for(ll i=s;i<d;i=nx)
{
ll ss = 0;
nx = i+1; while(col[nx] !=3) nx++;
plen = 0;
for(ll j=i+1;j<nx;j++)
{
if(col[j] == 1) p[++plen] = j;
}
ll minx = LLONG_MAX;
for(ll j=0;j<=plen;j++)
{
ll o = 0; if(j) o += a[p[j]] - a[i]; if(j+1<=plen) o += a[nx] - a[p[j+1]];
minx = min(minx , o);
}ss+=minx;
plen = 0;
for(ll j=i+1;j<nx;j++)
{
if(col[j] == 2) p[++plen] = j;
}
minx = LLONG_MAX;
for(ll j=0;j<=plen;j++)
{
ll o = 0; if(j) o += a[p[j]] - a[i]; if(j+1<=plen) o += a[nx] - a[p[j+1]];
minx = min(minx , o);
}ss+=minx;
ss += a[nx] - a[i];
ss = min(ss , 2 * (a[nx] - a[i]));
// printf("%lld\n",ss);
ans += ss;
}
return printf("%lld\n",ans),0;
}
F
题意
问哪些边在简单环上
分析
简单环就是一个点联通分量,点数和边数相同,一条边找到dfs序比较大的点,也就是深度比较大的点,这条边属于的联通分量就是这条边属于的联通分量
(因为可能一个点属于多个联通分量)
代码
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N = 1234567;
inline int read()
{
int p=0; int f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
struct node{int x,y,next;}edge[N]; int len,first[N];
void ins(int x,int y){len++; edge[len].x=x; edge[len].y=y; edge[len].next=first[x]; first[x]=len;}
int dfn[N],low[N],id=0,cnt=0; stack<int> s; int n,m;
vector<int> scc[N]; int bel[N];
void dfs(int x)
{
dfn[x] = low[x] = ++id; s.push(x);
for(int k=first[x];k!=-1;k=edge[k].next)
{
int y = edge[k].y;
if(dfn[y]==-1)
{
dfs(y); low[x] = min(low[x] , low[y]);
if(low[y] >= dfn[x])
{
cnt++; scc[cnt].pb(x); int i;
do
{
i = s.top();
scc[cnt].pb(i); bel[i] = cnt; s.pop();
}while(i!=y);
}
}
else low[x] = min(low[x],dfn[y]);
}
}
vector<int> siz[N];
vector<int>v;
int main()
{
len = 1; memset(first,-1,sizeof(first));
n = read(); m = read();
for(int i=1;i<=m;i++)
{
int x = read(); int y = read();
ins(x,y); ins(y,x);
}
memset(dfn,-1,sizeof(dfn));
memset(low,-1,sizeof(low));
//dfs(3);
cnt = 0; for(int i=1;i<=n;i++) if(dfn[i] == -1){while(!s.empty()) s.pop();
dfs(i);}
for(int i=2;i<=len;i+=2)
{
int p = dfn[edge[i].x] > dfn[edge[i].y] ? edge[i].x : edge[i].y;
siz[bel[p]].pb(i/2);
}
for(int i=1;i<=cnt;i++)
{
if(scc[i].size() == siz[i].size()) for(auto j:siz[i]) v.pb(j);
}
printf("%d\n",v.size()); sort(v.begin(),v.end());
for(int i=0;i<v.size();i++) printf("%d%c",v[i]," \n"[i==v.size()-1]);
return 0;
}