【题意】:
Linux 用户和 OSX 用户一定对软件包管理器不会陌生。通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置。Debian/Ubuntu 使用的 apt-get,Fedora/CentOS 使用的 yum,以及 OSX 下可用的 Homebrew 都是优秀的软件包管理器。
你决定设计你自己的软件包管理器。不可避免地,你要解决软件包之间的依赖问题。如果软件包 AA 依赖软件包 BB,那么安装软件包 AA 以前,必须先安装软件包 BB。同时,如果想要卸载软件包 BB,则必须卸载软件包 AA。现在你已经获得了所有的软件包之间的依赖关系。而且,由于你之前的工作,除 00 号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而 00 号软件包不依赖任何一个软件包。依赖关系不存在环(若有m(m≥2)个软件包A1,A2,A3,…,Am ,其中 A1 依赖 A2,A2依赖 A3 ,A3依赖 A4 ,……,Am−1 依赖 Am ,而 Am 依赖 A1 ,则称这 m 个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。
现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为 0。
【思路】:首先,根据题意,这依赖关系形成了一棵树,所以我们首先进行树链剖分
接下来让我们考虑如何用线段树来维护信息:
记Tag[o]为线段树上编号为o的点的状态(-1表示不知道,0表示未安装,1表示以安装),一开始肯定全部清0,sum[o]表示线段树上编号为o的点的子树v中Tag[v]的点的个数
所以,接下来的维护很简单了,具体看代码。
【代码】:
#include
using namespace std;
#define gc getchar()
#define g(c) isdigit(c)
inline int read(){
char c=0;int x=0;bool f=0;
while (!g(c)) f=c=='-',c=gc;
while (g(c)) x=x*10+c-48,c=gc;
return f?-x:x;
}
const int N=1e5+3e2;
struct node{
int next,to;
}e[N];int h[N],tot;
inline void add(int a,int b){
e[++tot]=(node){h[a],b};h[a]=tot;
}
int dep[N],sze[N],son[N];
int fa[N],seg[N],rev[N];
int top[N],dfscnt;
void dfs1(int u,int f){
dep[u]=dep[f]+1;sze[u]=1;fa[u]=f;
int maxdep=-1,heavyson=0;
for(int i=h[u];i;i=e[i].next){
register int v=e[i].to;
if (v==f) continue;dfs1(v,u);
if (sze[v]>maxdep){
maxdep=sze[v];
heavyson=v;
}
sze[u]+=sze[v];
}
son[u]=heavyson;
}
void dfs2(int u,int Top){
if (son[u]){
seg[son[u]]=++dfscnt;
rev[dfscnt]=son[u];
top[son[u]]=Top;
dfs2(son[u],Top);
}
else return;
for(int i=h[u];i;i=e[i].next){
register int v=e[i].to;
if (v!=fa[u]&&v!=son[u]){
seg[v]=++dfscnt;
rev[dfscnt]=v;
top[v]=v;dfs2(v,v);
}
}
return;
}
int Tag[N<<2],sum[N<<2];
inline void pushup(int o){
sum[o]=sum[o<<1]+sum[o<<1|1];
}
inline void pushdown(int o,int l,int r){
Tag[o<<1]=Tag[o];Tag[o<<1|1]=Tag[o];
register int mid=(l+r)>>1;
sum[o<<1]=Tag[o]*(mid-l+1);
sum[o<<1|1]=Tag[o]*(r-mid);
Tag[o]=-1;return;
}
void build(int o,int l,int r){
if (l==r){
sum[o]=0;return;
}
int mid=(l+r)>>1;
build(o<<1,l,mid);
build(o<<1|1,mid+1,r);
pushup(o);return;
}
void update(int o,int l,int r,int p,int q,int v){
if (p<=l&&r<=q){
sum[o]=v*(r-l+1);
Tag[o]=v;return;
}
if (l>q||r>1;
update(o<<1,l,mid,p,q,v);
update(o<<1|1,mid+1,r,p,q,v);
pushup(o);return;
}
int lst,i,n,m,x;
char opt[20];
inline void change(int x,int y){
while (top[x]!=top[y]){
if (dep[top[x]]dep[y]) swap(x,y);
update(1,1,n,seg[x],seg[y],1);
}
int main(){
freopen("t1.in","r",stdin);
n=read();
for(i=2;i<=n;i++){
x=read()+1;add(x,i);
}
rev[1]=dfscnt=1;
seg[1]=top[1]=1;//别忘了这两行哦
dfs1(1,0);dfs2(1,1);
build(1,1,n);m=read();
for(i=1;i<=m;i++){
scanf("%s",opt+1);
x=read()+1;lst=sum[1];
switch(opt[1]){
case 'i':change(1,x);break;
case 'u':update(1,1,n,seg[x],seg[x]+sze[x]-1,0);break;
// seg[x]+sze[x]-1表示以x为根的子树的节点的seg值的最大值
}
printf("%d\n",abs(sum[1]-lst));//别忘了abs
}
return 0;
}
【题意】:给定一个具有N个顶点的凸多边形,将顶点从 1至 N标号,每个顶点的权值都是一个正整数。将这个凸多边形划分成 个互不相交的三角形,试求这些三角形顶点的权值乘积和至少为多少。
【思路】:记f[i][j]表示把顶点i到j分为很多个三角形的最小权值和,则,其中s[i]表示顶点i的权值
最后,别忘了打高精哦(个人推荐把高精封装到一个结构体里,这样使用非常方便)
【代码】:
//By hpwwzyy2012
#include
using namespace std;
const int N=1100;
struct node{
int a[N],len;
node(){
memset(a,0,sizeof(a));
len=0;
}//清空高精数
node operator = (int c){
if (c==0) len=1;
while (c){
a[++len]=c%10;
c/=10;
}
return *this;
}//赋值高精数(把高精数赋值一个低精数)
node operator = (string s){
len=s.length();
for(int i=0;i1&&c.a[c.len]==0) c.len--;
return c;
}//高精乘
node operator + (node b){
node c;c.len=max(len,b.len);
register int x=0,i;
for(i=1;i<=c.len;i++){
c.a[i]=a[i]+b.a[i]+x;
x=c.a[i]/10;c.a[i]%=10;
}
if (x) c.a[++c.len]=x;
return c;
}//高精加
bool operator < (node b){
if (lenb.len) return false;
for(int i=len;i;i--){
if (a[i]b.a[i]) return false;
}
return false;
}//高精比较
void read(){
string s;
cin>>s;
*this=s;
}//输入
void write(){
// printf("len=%d\n",len);
for(int i=len;i;i--)
printf("%d",a[i]);
// printf("\n");
}//输出
}f[60][60],s[60];int n;
inline void read_the_date(){
cin>>n;int i;
for(i=1;i<=n;i++)
s[i].read();
return;
}//读入数据
inline node Min(node a,node b){
if (a