二期鸡熏
8/12:
困。
8/13:
8/14:
8/15:
% 你赛万元神去了,没时间写。
8/16:
% 你赛万元神去了,没时间写。
8/17:
% 你赛万元神去了,没时间写。
8/18:
搜索专题。
[NOIP2015 提高组] 斗地主 加强版 题解 BFS+DFS。
点击查看代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline int read()
{
int x = 0, c = getchar(), f = 0;
for (; c > '9' || c < '0'; f = c == '-', c = getchar())
;
for (; c >= '0' && c <= '9'; c = getchar())
x = (x << 1) + (x << 3) + (c ^ 48);
return f ? -x : x;
}
unordered_map<ll, int> mp;
// mp[s] : 所有出过的牌的状态为 s 时,达成这个状态的最小次数。
int a[30]; // 排集
int n;
const ll ksm[15] = {1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625, 1220703125, 6103515625};
// 5 进制状压
// 每一位存
int t[16] = {};
// 存每个点数出现了多少张牌
int st[30] = {}, tail = 0;
// 存手里还剩的牌的点数
int ans = 0, ans_cnt = 0;
// ans: 最小次数 ; ans_cnt:最小次数由哪个 cnt 被更新过来
struct Node
{
int cnt; // 现在打了多少次牌
ll use; // use:所有出过的牌的状态
ll unuse; // unuse:所有没出的牌的状态
};
queue<Node> q; // BFS
// 更新答案
inline void get(const int &cnt, ll use, ll unuse)
{
if (mp.count(use))
return; // 广搜一定是更优的状态先被搜到,所以之前搜到过则直接返回
mp[use] = mp[use] == 0 ? cnt : min(cnt, mp[use]); // 更新打出牌状态为 use 的最小次数
if (mp.count(unuse)) // 如果
ans = (ans == 0 ? cnt + mp[unuse] : min(ans, cnt + mp[unuse])), ans_cnt = cnt;
else
q.push({cnt, use, unuse});
}
/*
一共打了 cnt 次,
现在要选择打或不打 st[pos] 这张牌,
到现在出的牌的状态为 use,没出过的牌的状态为 unuse,
一共打了
cnt1 个单,
cnt2 个对
cnt3 个三
cnt4 个四
,
上一个打出的牌是 last,若没有则为 -114514,
pd 记录可否构成顺子
*/
void dfs(const int &cnt, int pos, ll use, ll unuse, int cnt1, int cnt2, int cnt3, int cnt4, int last, bool pd)
{
if (ans && cnt != ans_cnt)
return; // 非最优,返回
if (pos > tail)
return; // 没牌返回
int num = st[pos];
int c = t[num];
if (num == 0)
{
get(cnt, use + 1, unuse - 1); // 0
if (c == 2) // 0+0
get(cnt, use + 2, unuse - 2);
dfs(cnt, pos + 1, use + 1, unuse - 1, 1, cnt2, cnt3, cnt4, 0, 0); // 0 + ?
dfs(cnt, pos + 1, use, unuse, cnt1, cnt2, cnt3, cnt4, last, pd); // ?
return;
}
if (c >= 4)
{
if (cnt1 == 2 && !cnt2 && !cnt3 && !cnt4) // 4+1+1
get(cnt, use + ksm[num] * 4, unuse - ksm[num] * 4);
if (!cnt1 && cnt2 == 2 && !cnt3 && !cnt4) // 4+2+2
get(cnt, use + ksm[num] * 4, unuse - ksm[num] * 4);
if (!cnt1 && !cnt2 && !cnt3 && !cnt4) // 4+0
get(cnt, use + ksm[num] * 4, unuse - ksm[num] * 4);
if (cnt1 == 1 && !cnt2 && !cnt3 && !cnt4) // 4+1+?
dfs(cnt, pos + 1, use + ksm[num] * 4, unuse - ksm[num] * 4, cnt1, cnt2, cnt3, cnt4 + 1, num, 0);
if (!cnt1 && cnt2 == 1 && !cnt3 && !cnt4) // 4+2+?
dfs(cnt, pos + 1, use + ksm[num] * 4, unuse - ksm[num] * 4, cnt1, cnt2, cnt3, cnt4 + 1, num, 0);
if (!cnt1 && !cnt2 && !cnt3 && !cnt4)
{
dfs(cnt, pos + 1, use + ksm[num] * 4, unuse - ksm[num] * 4, cnt1, cnt2, cnt3, cnt4 + 1, num, 0); // 4+?
dfs(cnt, pos + 1, use + ksm[num] * 4, unuse - ksm[num] * 4, cnt1, cnt2 + 2, cnt3, cnt4, num, 0); // 2+2+?
}
}
if (c >= 3)
{
if (cnt1 == 1 && !cnt2 && !cnt3 && !cnt4) // 3+1
get(cnt, use + ksm[num] * 3, unuse - ksm[num] * 3);
if (!cnt1 && cnt2 == 1 && !cnt3 && !cnt4) // 3+2
get(cnt, use + ksm[num] * 3, unuse - ksm[num] * 3);
if (!cnt1 && !cnt2 && !cnt3 && !cnt4) // 3
get(cnt, use + ksm[num] * 3, unuse - ksm[num] * 3);
if (!cnt1 && !cnt2 && !cnt3 && !cnt4 && (!pd || (pd && (last < 0 || last == 2 || num != last + 1)))) // 3+? 且不可能构成顺子(剪枝)
dfs(cnt, pos + 1, use + ksm[num] * 3, unuse - ksm[num] * 3, cnt1, cnt2, cnt3 + 1, cnt4, num, 0);
}
if (c >= 2)
{
if (!cnt1 && cnt2 == 1 && !cnt3 && cnt4 == 1) // 2+4+2
get(cnt, use + ksm[num] * 2, unuse - ksm[num] * 2);
if (!cnt1 && !cnt2 && cnt3 == 1 && !cnt4) // 2+3
get(cnt, use + ksm[num] * 2, unuse - ksm[num] * 2);
if (!cnt1 && !cnt2 && !cnt3 && cnt4 == 1) // 1+1+4
get(cnt, use + ksm[num] * 2, unuse - ksm[num] * 2);
if (!cnt1 && !cnt2 && !cnt3 && !cnt4) // 2
get(cnt, use + ksm[num] * 2, unuse - ksm[num] * 2);
if (!cnt1 && !cnt2 && !cnt3 && (!pd || (pd && (last < 0 || last == 2 || num != last + 1)))) // 2+? // 2+4+? 且不可能构成顺子(剪枝)
dfs(cnt, pos + 1, use + ksm[num] * 2, unuse - ksm[num] * 2, cnt1, cnt2 + 1, cnt3, cnt4, num, 0);
if (!cnt1 && cnt2 == 1 && !cnt3 && !cnt4 && (!pd || (pd && (last < 0 || last == 2 || num != last + 1)))) // 2+2+?(4) 且不可能构成顺子(剪枝)
dfs(cnt, pos + 1, use + ksm[num] * 2, unuse - ksm[num] * 2, cnt1, cnt2 + 1, cnt3, cnt4, num, 0);
}
if (c >= 1)
{
if (!cnt1 && !cnt2 && cnt3 == 1 && !cnt4)
get(cnt, use + ksm[num] * 1, unuse - ksm[num] * 1); // 1+3
if (cnt1 == 1 && !cnt2 && !cnt3 && cnt4 == 1)
get(cnt, use + ksm[num] * 1, unuse - ksm[num] * 1); // 1+1+4
if (!cnt1 && !cnt2 && !cnt3 && !cnt4)
get(cnt, use + ksm[num] * 1, unuse - ksm[num] * 1); // 1+0
if (!cnt1 && !cnt2 && !cnt3 && cnt4 <= 1 && (!pd || (pd && (last < 0 || last == 2 || num != last + 1)))) // 1+? // 1+4+? 且不可能构成顺子(剪枝)
dfs(cnt, pos + 1, use + ksm[num] * 1, unuse - ksm[num] * 1, cnt1 + 1, cnt2, cnt3, cnt4, num, 0);
if (cnt1 == 1 && !cnt2 && !cnt3 && !cnt4 && (!pd || (pd && (last < 0 || last == 2 || num != last + 1)))) // 1+1+?(4) 且不可能构成顺子(剪枝)
dfs(cnt, pos + 1, use + ksm[num] * 1, unuse - ksm[num] * 1, cnt1 + 1, cnt2, cnt3, cnt4, num, 0);
}
if (num > 2 && pd) // 可能构成顺子
{
if ((last + 1 == num && last != 2) || last < 0) // 可能构成顺子
{
if (c >= 3 && !cnt1 && !cnt2 && !cnt4)
{
if (cnt3 >= 1) // 3+3+...
get(cnt, use + ksm[num] * 3, unuse - ksm[num] * 3);
dfs(cnt, pos + 1, use + ksm[num] * 3, unuse - ksm[num] * 3, cnt1, cnt2, cnt3 + 1, cnt4, num, pd && (last + 1 == num || last < 0));
// 尝试构成 3 顺
}
if (c >= 2 && !cnt1 && !cnt3 && !cnt4)
{
if (cnt2 >= 2) // 2+2+2+...
get(cnt, use + ksm[num] * 2, unuse - ksm[num] * 2);
dfs(cnt, pos + 1, use + ksm[num] * 2, unuse - ksm[num] * 2, cnt1, cnt2 + 1, cnt3, cnt4, num, pd && (last + 1 == num || last < 0));
// 尝试构成对顺
}
if (c >= 1 && !cnt2 && !cnt3 && !cnt4)
{
if (cnt1 >= 4) // 1+1+1+1+1+...
get(cnt, use + ksm[num] * 1, unuse - ksm[num] * 1);
dfs(cnt, pos + 1, use + ksm[num] * 1, unuse - ksm[num] * 1, cnt1 + 1, cnt2, cnt3, cnt4, num, pd && (last + 1 == num || last < 0));
// 尝试构成单顺
}
}
}
dfs(cnt, pos + 1, use, unuse, cnt1, cnt2, cnt3, cnt4, last, pd);
// 不出这个点数的牌
}
void solve()
{
// 注意清空 !!!!!
ans = 0;
ans_cnt = -1;
while (q.size()) q.pop();
mp.clear();
for (int i = 1; i <= n; i++)
{
a[i] = read();
if (a[i] == 1) a[i] += 13;
read();
}
sort(a + 1, a + 1 + n);
ll ansssss = 0;
for (int i = 1; i <= n; i++) ansssss += ksm[a[i]];
q.push({0, 0, ansssss});
mp[0] = 0;
if (n)
{
while (q.size())
{
int cnt = q.front().cnt + 1;
ll use = q.front().use, unuse = q.front().unuse, x = unuse;
if (ans && cnt != ans_cnt) break; // 搜到过且不可能有最优状态,则退出循环
if (mp.count(unuse)) // 剪枝
ans = (ans == 0 ? cnt - 1 + mp[unuse] : min(ans, cnt - 1 + mp[unuse])), ans_cnt = cnt - 1;
q.pop();
tail = 0;
memset(t, 0, sizeof(t));
// 记录每个点数还需要出多少张牌
for (int i = 0; i < 15; i++)
{
t[i] += x % 5;
x /= 5;
if (t[i]) st[++tail] = i;
}
dfs(cnt, 1, use, unuse, 0, 0, 0, 0, -114514, 1);
}
}
cout << ans << "\n";
}
signed main()
{
int T = read();
n = read();
while (T--) solve();
return 0;
}
Anya and Cubes 折半搜索。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,k,s;
int c[30],a[30],b[30];
int cnta,cntb;
unordered_map<int,int> mp[30];
int frac[30];
void dfs1(int pos,int cnt,int sum)
{
// cout<<pos<<" "<<a[pos]<<"\n";
// cout<<pos<<" "<<cnt<<" "<<sum<<"\n";
// cout<<pos<<" "<<cnt<<" "<<k<<" "<<sum<<" "<<s<<"\n";
if(cnt>k) return;
if(sum>s) return;
if(pos>cnta)
{
// cout<<pos<<" "<<cnt<<" "<<sum<<"\n";
mp[cnt][sum]++;
// cout<<cnt<<" "<<sum<<"\n";
return;
}
// cout<<"1\n";
dfs1(pos+1,cnt,sum);
// cout<<"2 "<<a[pos]<<" frac[a[pos]]="<<frac[a[pos]]<<"\n";
if(a[pos]<=19)dfs1(pos+1,cnt+1,sum+frac[a[pos]]);
// cout<<"3\n";
dfs1(pos+1,cnt,sum+a[pos]);
}
int ans=0;
void dfs2(int pos,int cnt,int sum)
{
if(cnt>k) return;
if(sum>s) return;
if(pos>cntb)
{
for(int i=k-cnt;i>=0;i--)
if(mp[i].count(s-sum)) ans+=mp[i][s-sum];
return;
}
dfs2(pos+1,cnt,sum);
if(b[pos]<=18)dfs2(pos+1,cnt+1,sum+frac[b[pos]]);
dfs2(pos+1,cnt,sum+b[pos]);
}
signed main()
{
frac[0]=1;
for(int i=1;i<=18;i++) frac[i]=frac[i-1]*i;
// #ifndef ONLINE_JUDGE
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
// #endif
//mt19937_64 myrand(time(0));
n=read();
k=read();
s=read();
if(n==1)
{
int x=read();
if(x<=18) ans+=frac[x]==s;
ans+=x==s;
cout<<ans;
return 0;
}
for(int i=1;i<=n;i++)
{
c[i]=read();
if(i<=(n>>1)) a[++cnta]=c[i];
else b[++cntb]=c[i];
}
dfs1(1,0,0);
dfs2(1,0,0);
cout<<ans<<"\n";
return 0;
}
[蓝桥杯 2023 省 A] 买瓜 还是折半搜索,注意要把瓜排序,要不然会 TLE。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,m;
// int a[1005];
unordered_map<signed,char> mp;
unordered_map<signed,bool> vis;
int a[105],b[105],cnta,cntb;
ll f2[105];
ll f[100];
int ans=0x3f3f3f3f;
inline int min(int x,int y) { return x<y?x:y; }
void dfs1(int pos,int cnt,int sum)
{
// cout<<pos<<" sum="<<sum<<" "<<sum+f2[cnta]-f2[pos-1]+f[cntb]<<"<"<<m<<"\n";
// if(cnt>k) return;
if(sum>m) return;
if(sum+f2[cnta]-f2[pos-1]+f[cntb]<m) return;
// if(sum>m) return;
if(pos>cnta)
{
if(!vis[sum]) vis[sum]=1,mp[sum]=cnt;
// cout<<sum<<"\n";
mp[sum]=min(mp[sum],cnt);
return;
}
dfs1(pos+1,cnt,sum);
dfs1(pos+1,cnt,sum+a[pos]);
dfs1(pos+1,cnt+1,sum+(a[pos]>>1));
}
void dfs2(int pos,int cnt,int sum)
{
if(sum>m) return;
if(cnt>=ans) return;
if(sum+f[cntb]-f[pos-1]+f2[cnta]<m) return;
if(sum+f[cntb]-f[pos-1]==m)
{
ans=cnt;
return;
}
// cout<<pos<<" "<<sum+f[cntb]-f[pos-1]+f[cnta]<<" "<<m<<"\n";
// if(sum+(f2[cnta]>>1)>m) return;
if(pos>cntb)
{
// cout<<sum<<"\n";
if(vis.count(m-sum)) ans=min(ans,cnt+mp[m-sum]);
return;
}
dfs2(pos+1,cnt,sum+b[pos]);
dfs2(pos+1,cnt+1,sum+(b[pos]>>1));
dfs2(pos+1,cnt,sum);
}
signed main()
{
// #ifndef ONLINE_JUDGE
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
// #endif
//mt19937_64 myrand(time(0));
n=read();
m=read()<<1;
int x[33]={};
for(int i=1;i<=n;i++)
{
x[i]=read()<<1;
}
std::sort(x+1,x+n+1,std::greater<ll>());
// std::sort(b+1,b+cntb+1,std::greater<ll>());
for(int i=1;i<=n;i++)
{
if(i<=(n>>1)) a[++cnta]=x[i];
else b[++cntb]=x[i];
}
if(n==1)
{
// cout<<"nakna";
if(b[1]==m) cout<<"0\n";
else if((m<<1)==b[1]) cout<<"1\n";
else cout<<"-1\n";
return 0;
}
for(int i=1;i<=cntb;i++) f[i]=f[i-1]+b[i];
for(int i=1;i<=cnta;i++) f2[i]=f2[i-1]+a[i];
dfs1(1,0,0);
// cout<<"\n\n";
dfs2(1,0,0);
if(ans>1000) ans=-1;
cout<<ans;
return 0;
}
8/19:
DP 专题。
先对原树进行树剖,然后和正常树剖一样建线段树,线段树每个节点设:
\(dp[p][k]\) 表示在点 \(p\) 所管辖的 dfn 序区间内任意节点任选 \(k\) 个人,所得到的最大价值。
\(g[p][k]\) 表示在点 \(p\) 所管辖的 dfn 序区间内只在 \(1\) 个节点选 \(k\) 个人,所得到的最大价值。
叶子结点初始化 \(dp[p]=g[p]=T[dfn[p]]\)。
对于非叶子节点,显然我们有转移:
设左子树编号为 \(lp=(p<<1)\) ,右子树编号为 \(rp=(p<<1)|1\)。
修改操作直接修改即可。
查询时和修改一样,
a <- ans1 防止后效性, $$ans1[p][i+j]=\max(a[i]+dp[p][j]), i+j \le m$$
8/20:
8/21:
8/22:
机房断电,放假
8/23:
图论专题。
把所有木材长度预处理然后去重,跑同余最短路即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,m;
int l[3005];
int cnt;
bool vis[10005];
priority_queue<pair<int,int> ,vector<pair<int,int> >,greater<pair<int,int> > > q;
int dis[3005];
signed main()
{
n=read();
m=read();
for(int i=1;i<=n;i++)
{
int x=read();
for(int j=0;j<=m&&x-j>0;j++)
{
if(vis[x-j]) continue;
vis[x-j]=1;
}
}
for(int i=1;i<=3000;i++) if(vis[i]) l[++cnt]=i;
// for(int i=1;i<=cnt;i++) cout<<l[i]<<" ";
// cout<<"\n";
q.push(make_pair(0,0));
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
sort(l+1,l+1+cnt);
dis[0]=0;
const int mod=l[1];
while(q.size())
{
int nw=q.top().second;
q.pop();
if(vis[nw]) continue;
vis[nw]=1;
// cout<<"nw="<<nw<<"\n";
for(int i=2;i<=cnt;i++)
{
int to=(l[i]+nw);
int dt=to/mod;
to%=mod;
if(dis[to]>dis[nw]+dt)
{
dis[to]=dis[nw]+dt;
q.push(make_pair(dis[to],to));
}
// cout<<" -> to "<<to<<"\n";
}
}
int ans=-1;
for(int i=0;i<mod;i++)
{
// cout<<dis[i]<<" ";
// cout<<"\n";
if(dis[i]>0&&dis[i]<100000) ans=max(ans,i+(dis[i]-1)*mod);
}
cout<<ans<<"\n";
// #ifndef ONLINE_JUDGE
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout);
// #endif
//mt19937_64 myrand(time(0));
return 0;
}
妙妙题。
先将询问差分成 \([1,r] - [1,l-1]\) 两部分。
求前缀 deep[lca] 可以转化为:从前往后枚举点 \(i\),先根链 \(+1\) 加入 \(i\) 点,再算答案求根链和。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int N=1e5+5;
int n,m;
vector<int> E[N];
int fa[N];
int siz[N],dfn[N],top[N],son[N],dep[N],tot;
int sum[N<<2],lazy[N<<2];
#define pushdown() \
{ \
lazy[lp] += lazy[p]; \
lazy[rp] += lazy[p]; \
sum[lp] += lazy[p] * (mid - l + 1); \
sum[rp] += lazy[p] * (r - mid); \
lazy[p] = 0; \
}
void add(int l,int r,int sl,int sr,int k,int p)
{
if(sl<=l&&r<=sr)
{
sum[p]+=k*(r-l+1);
lazy[p]+=k;
return;
}
int lp=(p<<1),rp=(p<<1)|1,mid=(l+r)>>1;
if(lazy[p]) pushdown()
if(sl<=mid) add(l,mid,sl,sr,k,lp);
if(sr>mid) add(mid+1,r,sl,sr,k,rp);
sum[p]=sum[lp]+sum[rp];
}
int query(int l,int r,int sl,int sr,int p)
{
if(sl<=l&&r<=sr) return sum[p];
int lp=(p<<1),rp=(p<<1)|1,mid=(l+r)>>1,ans=0;
if(lazy[p]) pushdown()
if(sl<=mid) ans=query(l,mid,sl,sr,lp);
if(sr>mid) ans+=query(mid+1,r,sl,sr,rp);
sum[p]=sum[lp]+sum[rp];
return ans;
}
void dfs1(int p,int fa)
{
siz[p]=1;
dep[p]=dep[fa]+1;
for(int to:E[p])
{
if(to==fa) continue;
dfs1(to,p);
// cerr<<p<<" "<<to<<"\n";
siz[p]+=siz[to];
// cerr<<son[p]<<" "<<siz[son[p]]<<" "<<siz[to]<<"\n";
if(siz[to]>siz[son[p]]) son[p]=to;
}
}
void dfs2(int p,int tp)
{
dfn[p]=++tot;
// add(1,n,tot,tot,0,1);
top[p]=tp;
if(son[p]) dfs2(son[p],tp);
for(int to:E[p])
if(!dfn[to]) dfs2(to,to);
}
int query(int u)
{
// if(u==3) return 0;
int ans=0;
while(top[u]!=1) ans+=query(1,n,dfn[top[u]],dfn[u],1),u=fa[top[u]];//,cerr<<"u "<<u<<"\n";
ans+=query(1,n,dfn[1],dfn[u],1);
return ans;
}
void add(int u)
{
while(top[u]!=1) add(1,n,dfn[top[u]],dfn[u],1,1),u=fa[top[u]];
add(1,n,dfn[1],dfn[u],1,1);
}
struct Qu{
int pos,op,z,id;
}ask[N<<1];
int cnt;
int ans[N];
bool cmp(Qu x,Qu y) { return x.pos<y.pos; }
signed main()
{
n=read();
m=read();
for(int i=2;i<=n;i++)
{
fa[i]=read()+1;
E[fa[i]].push_back(i);
}
dfs1(1,0);
dfs2(1,1);
// for(int i=1;i<=n;i++) cerr<<son[i]<<" ";
// cout<<"\n";
for(int i=1;i<=m;i++)
{
int l=read()+1,r=read()+1,z=read()+1;
ask[++cnt]={l-1,-1,z,i};
ask[++cnt]={r,1,z,i};
}
sort(ask+1,ask+1+cnt,cmp);
// return 0;
int nw=0;
for(int i=1;i<=cnt;i++)
{
// cerr<<"i="<<i<<" ask[i].pos="<<ask[i].pos<<" nw="<<nw<<" z="<<ask[i].z<<"\n";
while(nw<ask[i].pos)
{
// cerr<<"iubsdfbid";
nw++;
add(nw);
}
ans[ask[i].id]+=ask[i].op*query(ask[i].z);
}
for(int i=1;i<=m;i++) write(ans[i]%201314),putchar('\n');
return 0;
}
8/24:
图论专题。
8/25:
LCT(LiChao Tree)
基于斜率的李超树代码
#include<stdio.h>
#include<cmath>
#include<algorithm>
using std::swap;
using std::abs;
using std::min;
const int Size=(1<<20)+1;
char buf[Size],*p1=buf,*p2=buf;
char buffer[Size];
int op1=-1;
const int op2=Size-1;
#define getchar() \
(tt == ss && (tt=(ss=In)+fread(In, 1, 1 << 20, stdin), ss == tt) \
? EOF \
: *ss++)
char In[1<<20],*ss=In,*tt=In;
inline int read()
{
int x=0,c=getchar(),f=0;
for(;c>'9'||c<'0';f=c=='-',c=getchar());
for(;c>='0'&&c<='9';c=getchar())
x=(x<<1)+(x<<3)+(c^48);
return f?-x:x;
}
inline void write(int x)
{
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int MAXN=40000;
int n;
struct ed{
double y1,y2,k,mid;
int id;
}nw,t[MAXN<<3];
int root[1<<20];
int tot;
const double eps=1e-9;
void add(int l,int r,int p)
{
int mid=(l+r)>>1,lp=(p<<1),rp=(p<<1)|1;
nw.mid=(mid-l)*nw.k+nw.y1;
if(nw.mid>t[p].mid) swap(t[p],nw);
if(l==r)
{
if(abs(t[p].mid-nw.mid)<eps) t[p].id=min(t[p].id,nw.id==0?0x3f3f3f3f:nw.id);
return;
}
if(t[p].y1>nw.y1&&t[p].y2>nw.y2) return;
if(abs(t[p].k-nw.k)<eps&&abs(t[p].mid-nw.mid)<eps)
{
t[p].id=min(t[p].id,nw.id==0?0x3f3f3f3f:nw.id);
return;
}
if(abs(nw.mid-t[p].mid)<eps&&nw.k>t[p].k) swap(nw,t[p]);
if(t[p].k>nw.k) nw.y2=nw.y1+(mid-l)*nw.k,add(l,mid,lp);
else nw.y1=nw.y1+(mid-l+1)*nw.k,add(mid+1,r,rp);
}
void add(int l,int r,int sl,int sr,int y0,double k,int id,int p)
{
if(sl<=l&&r<=sr)
{
double y1=(l-sl)*k+y0,y2=(r-sl)*k+y0;
nw={y1,y2,k,0,id};
add(l,r,p);
return;
}
int mid=(l+r)>>1,lp=(p<<1),rp=(p<<1)|1;
if(sl<=mid) add(l,mid,sl,sr,y0,k,id,lp);
if(sr>mid) add(mid+1,r,sl,sr,y0,k,id,rp);
}
void query(double &ans,int &ans_id,int l,int r,int x,int p)
{
int mid=(l+r)>>1;
double nw=t[p].y1+(x-l)*t[p].k;
if(t[p].id)
{
if(nw>ans) ans=nw,ans_id=t[p].id;
else if(abs(nw-ans)<=eps) ans_id=min(ans_id,t[p].id);
}
if(l==r) return;
if(x<=mid) query(ans,ans_id,l,mid,x,p<<1);
if(x>mid) query(ans,ans_id,mid+1,r,x,(p<<1)|1);
}
signed main()
{
n=read();
int lastans=0,cnt=0;
while(n--)
{
int op=read();
if(op==0)
{
int x=read();
double ans=0;
x=(x+lastans-1+39989)%39989+1;
lastans=0x3f3f3f3f;
query(ans,lastans,1,MAXN,x,1);
if(lastans==0x3f3f3f3f)lastans=0;
write(lastans),putchar('\n');
}
else
{
int x0=read(),y0=read(),x1=read(),y1=read();
x0+=lastans-1;x0%=39989;x0++;
x1+=lastans-1;x1%=39989;x1++;
y0+=lastans-1;y0%=1000000000;y0++;
y1+=lastans-1;y1%=1000000000;y1++;
if(x0>x1) swap(x0,x1),swap(y0,y1);
double k=y1-y0;
if(x1==x0) y0=y1,k=1e9;
else k/=x1-x0;
add(1,MAXN,x0,x1,y0,k,++cnt,1);
}
}
return 0;
}
随贪:
https://www.luogu.com.cn/discuss/1142478
8/26:
8/27:
8/28:
以下是博客签名,正文无关
本文来自博客园,作者:Wy_x,转载请在文首注明原文链接:https://www.cnblogs.com/Wy-x/p/19034632
版权声明:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC-BY-NC-SA 4.0 协议)进行许可。

浙公网安备 33010602011771号